// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "sharing/nearby_sharing_service_impl.h"

#include <stdint.h>

#include <cctype>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <functional>
#include <ios>
#include <limits>
#include <memory>
#include <optional>
#include <queue>
#include <string>
#include <utility>
#include <vector>

#include "base/casts.h"
#include "gmock/gmock.h"
#include "protobuf-matchers/protocol-buffer-matchers.h"
#include "gtest/gtest.h"
#include "absl/base/thread_annotations.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "absl/synchronization/notification.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
#include "internal/analytics/mock_event_logger.h"
#include "internal/base/file_path.h"
#include "internal/base/files.h"
#include "internal/flags/nearby_flags.h"
#include "internal/platform/implementation/signin_attempt.h"
#include "internal/test/fake_account_manager.h"
#include "internal/test/fake_device_info.h"
#include "internal/test/fake_task_runner.h"
#include "internal/test/mock_account_observer.h"
#include "sharing/advertisement.h"
#include "sharing/analytics/analytics_recorder.h"
#include "sharing/attachment_container.h"
#include "sharing/certificates/fake_nearby_share_certificate_manager.h"
#include "sharing/certificates/nearby_share_certificate_manager_impl.h"
#include "sharing/certificates/nearby_share_decrypted_public_certificate.h"
#include "sharing/certificates/test_util.h"
#include "sharing/common/nearby_share_enums.h"
#include "sharing/common/nearby_share_prefs.h"
#include "sharing/constants.h"
#include "sharing/contacts/fake_nearby_share_contact_manager.h"
#include "sharing/fake_nearby_connections_manager.h"
#include "sharing/fast_initiation/fake_nearby_fast_initiation.h"
#include "sharing/fast_initiation/nearby_fast_initiation_impl.h"
#include "sharing/file_attachment.h"
#include "sharing/flags/generated/nearby_sharing_feature_flags.h"
#include "sharing/incoming_share_session.h"
#include "sharing/internal/api/mock_app_info.h"
#include "sharing/internal/api/mock_sharing_platform.h"
#include "sharing/internal/api/preference_manager.h"
#include "sharing/internal/test/fake_bluetooth_adapter.h"
#include "sharing/internal/test/fake_connectivity_manager.h"
#include "sharing/internal/test/fake_context.h"
#include "sharing/internal/test/fake_preference_manager.h"
#include "sharing/local_device_data/fake_nearby_share_local_device_data_manager.h"
#include "sharing/local_device_data/nearby_share_local_device_data_manager_impl.h"
#include "sharing/nearby_connection_impl.h"
#include "sharing/nearby_connections_manager.h"
#include "sharing/nearby_connections_types.h"
#include "sharing/nearby_sharing_service.h"
#include "sharing/nearby_sharing_settings.h"
#include "sharing/proto/enums.pb.h"
#include "sharing/proto/rpc_resources.pb.h"
#include "sharing/proto/wire_format.pb.h"
#include "sharing/share_target.h"
#include "sharing/share_target_discovered_callback.h"
#include "sharing/text_attachment.h"
#include "sharing/transfer_metadata.h"
#include "sharing/transfer_metadata_matchers.h"
#include "sharing/transfer_update_callback.h"
#include "sharing/wifi_credentials_attachment.h"

namespace nearby::sharing {
namespace {

using SendSurfaceState =
    ::nearby::sharing::NearbySharingService::SendSurfaceState;
using ::nearby::sharing::api::MockAppInfo;
using ::nearby::sharing::api::PreferenceManager;
using ::nearby::sharing::proto::DataUsage;
using ::nearby::sharing::proto::DeviceVisibility;
using ::nearby::sharing::proto::FastInitiationNotificationState;
using ::nearby::sharing::service::proto::ConnectionResponseFrame;
using ::nearby::sharing::service::proto::FileMetadata;
using ::nearby::sharing::service::proto::Frame;
using ::nearby::sharing::service::proto::IntroductionFrame;
using ::nearby::sharing::service::proto::PairedKeyResultFrame;
using ::nearby::sharing::service::proto::TextMetadata;
using ::nearby::sharing::service::proto::V1Frame;
using ::testing::_;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::UnorderedElementsAre;

// Used to wait for absl::Notification to finish.
constexpr absl::Duration kWaitTimeout = absl::Milliseconds(500);
constexpr absl::Duration kTaskWaitTimeout = absl::Seconds(2);

class MockTransferUpdateCallback : public TransferUpdateCallback {
 public:
  ~MockTransferUpdateCallback() override = default;

  MOCK_METHOD(void, OnTransferUpdate,
              (const ShareTarget& shareTarget,
               const AttachmentContainer& attachmentContainer,
               const TransferMetadata& transferMetadata),
              (override));
};

class MockShareTargetDiscoveredCallback : public ShareTargetDiscoveredCallback {
 public:
  ~MockShareTargetDiscoveredCallback() override = default;

  MOCK_METHOD(void, OnShareTargetDiscovered, (const ShareTarget& share_target),
              (override));
  MOCK_METHOD(void, OnShareTargetLost, (const ShareTarget& share_target),
              (override));
  MOCK_METHOD(void, OnShareTargetUpdated, (const ShareTarget& share_target),
              (override));
};

// Auto unregister the receive surface when it goes out of scope.
class ScopedReceiveSurface {
 public:
  ScopedReceiveSurface(NearbySharingServiceImpl* service,
                       TransferUpdateCallback* transfer_callback)
      : service_(service), transfer_callback_(transfer_callback) {}

  ~ScopedReceiveSurface() {
    absl::Notification notification;
    service_->UnregisterReceiveSurface(
        transfer_callback_,
        [&notification](NearbySharingService::StatusCodes status_codes) {
          notification.Notify();
        });
    notification.WaitForNotificationWithTimeout(kWaitTimeout);
  }

 private:
  NearbySharingServiceImpl* const service_;
  TransferUpdateCallback* const transfer_callback_;
};

// Auto unregister the send surface when it goes out of scope.
class ScopedSendSurface {
 public:
  ScopedSendSurface(NearbySharingServiceImpl* service,
                    TransferUpdateCallback* transfer_callback)
      : service_(service), transfer_callback_(transfer_callback) {}

  ~ScopedSendSurface() {
    absl::Notification notification;
    service_->UnregisterSendSurface(
        transfer_callback_,
        [&notification](NearbySharingService::StatusCodes status_codes) {
          notification.Notify();
        });
    notification.WaitForNotificationWithTimeout(kWaitTimeout);
  }

 private:
  NearbySharingServiceImpl* const service_;
  TransferUpdateCallback* const transfer_callback_;
};

}  // namespace

namespace NearbySharingServiceUnitTests {

constexpr absl::Duration kDelta = absl::Milliseconds(100);

constexpr char kServiceId[] = "NearbySharing";
constexpr char kDeviceName[] = "test_device_name";
constexpr ShareTargetType kDeviceType = ShareTargetType::kPhone;
constexpr char kEndpointId[] = "test_endpoint_id";
constexpr char kTextPayload[] = "Test text payload";
constexpr char kFourDigitToken[] = "1953";
constexpr absl::string_view kTestAccountId = "test_account";
constexpr uint8_t kVendorId = 0;

constexpr int64_t kFreeDiskSpace = 10000;

const std::vector<uint8_t>& GetToken() {
  static std::vector<uint8_t>* token = new std::vector<uint8_t>({0, 1, 2});
  return *token;
}

const std::vector<uint8_t>& GetPrivateCertificateHashAuthToken() {
  static std::vector<uint8_t>* private_certificate_hash_auth_token =
      new std::vector<uint8_t>({0x8b, 0xcb, 0xa2, 0xf8, 0xe4, 0x06});
  return *private_certificate_hash_auth_token;
}

const std::vector<uint8_t>& GetIncomingConnectionSignedData() {
  static std::vector<uint8_t>* incoming_connection_signed_data =
      new std::vector<uint8_t>(
          {0x30, 0x45, 0x02, 0x20, 0x4f, 0x83, 0x72, 0xbd, 0x02, 0x70, 0xd9,
           0xda, 0x62, 0x83, 0x5d, 0xb2, 0xdc, 0x6e, 0x3f, 0xa6, 0xa8, 0xa1,
           0x4f, 0x5f, 0xd3, 0xe3, 0xd9, 0x1a, 0x5d, 0x2d, 0x61, 0xd2, 0x6c,
           0xdd, 0x8d, 0xa5, 0x02, 0x21, 0x00, 0xd4, 0xe1, 0x1d, 0x14, 0xcb,
           0x58, 0xf7, 0x02, 0xd5, 0xab, 0x48, 0xe2, 0x2f, 0xcb, 0xc0, 0x53,
           0x41, 0x06, 0x50, 0x65, 0x95, 0x19, 0xa9, 0x22, 0x92, 0x00, 0x42,
           0x01, 0x26, 0x25, 0xcb, 0x8c});
  return *incoming_connection_signed_data;
}

const std::vector<uint8_t>& GetOutgoingConnectionSignedData() {
  static std::vector<uint8_t>* outgoing_connection_signed_data =
      new std::vector<uint8_t>(
          {0x30, 0x45, 0x02, 0x21, 0x00, 0xf9, 0xc9, 0xa8, 0x89, 0x96, 0x6e,
           0x5c, 0xea, 0x0a, 0x60, 0x37, 0x3a, 0x84, 0x7d, 0xf5, 0x31, 0x82,
           0x74, 0xb9, 0xde, 0x3f, 0x64, 0x1b, 0xff, 0x4f, 0x54, 0x31, 0x1f,
           0x9e, 0x63, 0x68, 0xca, 0x02, 0x20, 0x52, 0x43, 0x46, 0xa7, 0x6f,
           0xcb, 0x96, 0x50, 0x86, 0xfd, 0x6f, 0x9f, 0x7e, 0x50, 0xa7, 0xa0,
           0x9b, 0xdf, 0xae, 0x79, 0x42, 0x47, 0xd9, 0x60, 0x71, 0x91, 0x7a,
           0xbb, 0x81, 0x9b, 0x0d, 0x2e});
  return *outgoing_connection_signed_data;
}

constexpr int kFilePayloadId = 111;
constexpr int kPayloadSize = 1000000;

const std::vector<uint8_t>& GetValidIntroductionFramePayloadIds() {
  static std::vector<uint8_t>* valid_introduction_frame_payload_ids =
      new std::vector<uint8_t>({1, 2, 3, kFilePayloadId});
  return *valid_introduction_frame_payload_ids;
}

constexpr size_t kMaxCertificateDownloadsDuringDiscovery = 3u;
constexpr absl::Duration kCertificateDownloadDuringDiscoveryPeriod =
    absl::Seconds(10);

std::unique_ptr<Payload> GetFilePayload(int64_t payload_id) {
  FilePath path =
      Files::GetTemporaryDirectory().append(FilePath(absl::StrCat(payload_id)));
  InputFile input_file{path.ToString()};
  return std::make_unique<Payload>(input_file);
}

std::unique_ptr<Payload> GetTextPayload(int64_t payload_id,
                                        absl::string_view text) {
  return std::make_unique<Payload>(
      std::vector<uint8_t>(text.begin(), text.end()));
}

std::unique_ptr<Frame> GetValidIntroductionFrame() {
  IntroductionFrame* introduction_frame =
      IntroductionFrame::default_instance().New();
  auto text_metadatas = introduction_frame->mutable_text_metadata();
  introduction_frame->set_start_transfer(true);

  for (int i = 1; i <= 3; ++i) {
    nearby::sharing::service::proto::TextMetadata* text_metadata =
        nearby::sharing::service::proto::TextMetadata::default_instance().New();

    text_metadata->set_text_title(absl::StrCat("title ", i));
    text_metadata->set_type(
        static_cast<nearby::sharing::service::proto::TextMetadata::Type>(i));
    text_metadata->set_payload_id(i);
    text_metadata->set_size(kPayloadSize);
    text_metadata->set_id(i);

    text_metadatas->AddAllocated(text_metadata);
  }

  auto file_metadatas = introduction_frame->mutable_file_metadata();

  nearby::sharing::service::proto::FileMetadata* file_metadata =
      nearby::sharing::service::proto::FileMetadata::default_instance().New();
  file_metadata->set_name("unit_test_nearby_share_name_\x80");
  file_metadata->set_type(nearby::sharing::service::proto::FileMetadata::VIDEO);
  file_metadata->set_payload_id(kFilePayloadId);
  file_metadata->set_size(kPayloadSize);
  file_metadata->set_mime_type("mime type");
  file_metadata->set_id(100);
  file_metadatas->AddAllocated(file_metadata);

  V1Frame* v1_frame = V1Frame::default_instance().New();
  v1_frame->set_type(V1Frame::INTRODUCTION);
  v1_frame->set_allocated_introduction(introduction_frame);

  Frame* frame = Frame::default_instance().New();
  frame->set_version(Frame::V1);
  frame->set_allocated_v1(std::move(v1_frame));
  return std::unique_ptr<Frame>(frame);
}

std::unique_ptr<Frame> GetEmptyIntroductionFrame() {
  V1Frame* v1_frame = V1Frame::default_instance().New();
  v1_frame->set_type(V1Frame::INTRODUCTION);
  v1_frame->set_allocated_introduction(
      IntroductionFrame::default_instance().New());

  Frame* frame = Frame::default_instance().New();
  frame->set_version(Frame::V1);
  frame->set_allocated_v1(v1_frame);
  return std::unique_ptr<Frame>(frame);
}

std::unique_ptr<Frame> GetConnectionResponseFrame(
    ConnectionResponseFrame::Status status) {
  V1Frame* v1_frame = V1Frame::default_instance().New();
  v1_frame->set_type(V1Frame::RESPONSE);
  ConnectionResponseFrame* response_frame =
      ConnectionResponseFrame::default_instance().New();
  response_frame->set_status(status);
  v1_frame->set_allocated_connection_response(response_frame);

  Frame* frame = Frame::default_instance().New();
  frame->set_version(Frame::V1);
  frame->set_allocated_v1(v1_frame);
  return std::unique_ptr<Frame>(frame);
}

std::unique_ptr<Frame> GetCancelFrame() {
  V1Frame* v1_frame = V1Frame::default_instance().New();
  v1_frame->set_type(V1Frame::CANCEL);

  Frame* frame = Frame::default_instance().New();
  frame->set_version(Frame::V1);
  frame->set_allocated_v1(v1_frame);
  return std::unique_ptr<Frame>(frame);
}

std::unique_ptr<AttachmentContainer> CreateTextAttachments(
    std::vector<std::string> texts) {
  auto attachment_container = std::make_unique<AttachmentContainer>();
  for (auto& text : texts) {
    attachment_container->AddTextAttachment(
        TextAttachment(service::proto::TextMetadata::TEXT, std::move(text),
                       /*text_title=*/std::nullopt,
                       /*mime_type=*/std::nullopt));
  }
  return attachment_container;
}

std::unique_ptr<AttachmentContainer> CreateFileAttachments(
    std::vector<FilePath> file_paths) {
  auto attachment_container = std::make_unique<AttachmentContainer>();
  for (auto& file_path : file_paths) {
    attachment_container->AddFileAttachment(
        FileAttachment(std::move(file_path)));
  }
  return attachment_container;
}

std::unique_ptr<AttachmentContainer> CreateWifiCredentialAttachments(
    std::string ssid, std::string password) {
  auto attachment_container = std::make_unique<AttachmentContainer>();
  attachment_container->AddWifiCredentialsAttachment(WifiCredentialsAttachment(
      std::move(ssid), service::proto::WifiCredentialsMetadata::WPA_PSK,
      std::move(password)));
  return attachment_container;
}

class NearbySharingServiceImplTest : public testing::Test {
 public:
  struct PayloadInfo {
    std::unique_ptr<Payload> payload;
    std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener;
  };

  NearbySharingServiceImplTest() = default;
  ~NearbySharingServiceImplTest() override = default;

  void SetUp() override {
    ON_CALL(mock_sharing_platform_, GetDeviceInfo)
        .WillByDefault(ReturnRef(fake_device_info_));
    ON_CALL(mock_sharing_platform_, GetPreferenceManager)
        .WillByDefault(ReturnRef(preference_manager_));
    ON_CALL(mock_sharing_platform_, GetAccountManager)
        .WillByDefault(ReturnRef(fake_account_manager_));
    ON_CALL(mock_sharing_platform_, UpdateFileOriginMetadata)
        .WillByDefault(Return(true));
    auto mock_app_info = std::make_unique<StrictMock<MockAppInfo>>();
    mock_app_info_ = mock_app_info.get();
    EXPECT_CALL(mock_sharing_platform_, CreateAppInfo())
        .WillOnce(Return(std::move(mock_app_info)));
    NearbyShareLocalDeviceDataManagerImpl::Factory::SetFactoryForTesting(
        &local_device_data_manager_factory_);
    NearbyShareCertificateManagerImpl::Factory::SetFactoryForTesting(
        &certificate_manager_factory_);
    nearby_fast_initiation_factory_ =
        std::make_unique<FakeNearbyFastInitiation::Factory>();
    NearbyFastInitiationImpl::Factory::SetFactoryForTesting(
        nearby_fast_initiation_factory_.get());
    NearbyFlags::GetInstance().OverrideBoolFlagValue(
        config_package_nearby::nearby_sharing_feature::kEnableMediumWifiLan,
        true);

    prefs::RegisterNearbySharingPrefs(preference_manager_);
    auto fake_task_runner =
        std::make_unique<FakeTaskRunner>(fake_context_.fake_clock(), 1);
    sharing_service_task_runner_ = fake_task_runner.get();
    contact_manager_ = new FakeNearbyShareContactManager();
    fake_nearby_connections_manager_ = new FakeNearbyConnectionsManager();
    connection_ = std::make_unique<NearbyConnectionImpl>(fake_device_info_);
    fake_nearby_connections_manager_->set_send_payload_callback(
        [this](std::unique_ptr<Payload> payload,
               std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener>
                   listener) {
          // If there are no listeners, treat it as a control frame.
          if (listener.use_count() == 0) {
            auto frame = std::make_unique<Frame>();
            std::vector<uint8_t> data =
                std::move(payload->content.bytes_payload.bytes);
            frame->ParseFromArray(data.data(), data.size());
            absl::MutexLock lock(connection_output_mutex_);
            frames_data_.push(std::move(frame));
          } else {
            absl::MutexLock lock(connection_output_mutex_);
            written_payloads_.push(PayloadInfo(std::move(payload), listener));
          }
        });
    SetBluetoothIsPresent(true);
    SetBluetoothIsPowered(true);
    SetScreenLocked(false);
    SetLanConnected(true);
    analytics_recorder_ = std::make_unique<analytics::AnalyticsRecorder>(
        /*vendor_id=*/0, /*event_logger=*/nullptr);

    service_ = CreateService(std::move(fake_task_runner));
  }

  void TearDown() override {
    if (connection_) {
      connection_.reset();
    }
    Shutdown();
    NearbyFlags::GetInstance().OverrideBoolFlagValue(
        config_package_nearby::nearby_sharing_feature::kEnableMediumWifiLan,
        true);
    NearbyShareLocalDeviceDataManagerImpl::Factory::SetFactoryForTesting(
        nullptr);
    NearbyShareCertificateManagerImpl::Factory::SetFactoryForTesting(nullptr);
    NearbyFlags::GetInstance().ResetOverridedValues();
    nearby_fast_initiation_factory_.reset();
  }

  void SetLanConnected(bool connected) {
    FakeConnectivityManager* connectivity_manager =
        down_cast<FakeConnectivityManager*>(
            fake_context_.GetConnectivityManager());
    connectivity_manager->SetLanConnected(connected);
  }

  std::unique_ptr<NearbySharingServiceImpl> CreateService(
      std::unique_ptr<FakeTaskRunner> task_runner) {
    return std::make_unique<NearbySharingServiceImpl>(
        std::move(task_runner), &fake_context_, mock_sharing_platform_,
        /*nearby_share_client_factory=*/nullptr,
        absl::WrapUnique(fake_nearby_connections_manager_),
        absl::WrapUnique(contact_manager_),
        analytics_recorder_.get());
  }

  void SetVisibility(DeviceVisibility visibility) {
    service_->GetSettings()->SetVisibility(visibility);
    FlushTesting();
  }

  void SetFastInitiationNotificationState(
      FastInitiationNotificationState state) {
    service_->GetSettings()->SetFastInitiationNotificationState(state);
    FlushTesting();
  }

  void SetBluetoothIsPresent(bool present) {
    FakeBluetoothAdapter& bluetooth_adapter =
        down_cast<FakeBluetoothAdapter&>(fake_context_.GetBluetoothAdapter());
    bluetooth_adapter.ReceivedAdapterPresentChangedFromOs(present);
    FlushTesting();
  }

  void SetBluetoothIsPowered(bool powered) {
    FakeBluetoothAdapter& bluetooth_adapter =
        down_cast<FakeBluetoothAdapter&>(fake_context_.GetBluetoothAdapter());
    bluetooth_adapter.ReceivedAdapterPoweredChangedFromOs(powered);
    fake_context_.fake_clock()->FastForward(absl::Milliseconds(500));
    FlushTesting();
  }

  void SetLanIsConnected(bool connected) {
    FakeConnectivityManager* connectivity_manager =
        down_cast<FakeConnectivityManager*>(
            fake_context_.GetConnectivityManager());
    connectivity_manager->SetLanConnected(connected);
    FlushTesting();
  }

  void ReceiveMessageFromConnection(std::vector<uint8_t> bytes) {
    sharing_service_task_runner_->PostTask(
        [this, bytes]() { connection_->WriteMessage(bytes); });
    EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kWaitTimeout));
  }

  void FastForward(absl::Duration duration) {
    fake_context_.fake_clock()->FastForward(duration);
    FlushTesting();
  }

  void SetScreenLocked(bool locked) {
    fake_device_info_.SetScreenLocked(locked);
    FlushTesting();
  }

  void StartIncomingConnection() {
    std::vector<uint8_t> endpoint_info = CreateTestEndpointInfo();
    fake_nearby_connections_manager_->AcceptConnection(
        endpoint_info, kEndpointId, connection_.get());
    service_->OnIncomingConnection(kEndpointId, endpoint_info,
                                   connection_.get());
  }

  NearbySharingService::StatusCodes RegisterSendSurface(
      TransferUpdateCallback* transfer_callback,
      ShareTargetDiscoveredCallback* discovery_callback, SendSurfaceState state,
      Advertisement::BlockedVendorId vendor_id =
          static_cast<Advertisement::BlockedVendorId>(kVendorId)) {
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->RegisterSendSurface(
        transfer_callback, discovery_callback, state, vendor_id,
        /*disable_wifi_hotspot=*/false,
        [&](NearbySharingService::StatusCodes status_codes) {
          result = status_codes;
          notification.Notify();
        });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    return result;
  }

  NearbySharingService::StatusCodes UnregisterSendSurface(
      TransferUpdateCallback* transfer_callback) {
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->UnregisterSendSurface(
        transfer_callback, [&](NearbySharingService::StatusCodes status_codes) {
          result = status_codes;
          notification.Notify();
        });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    return result;
  }

  NearbySharingService::StatusCodes RegisterReceiveSurface(
      TransferUpdateCallback* transfer_callback,
      NearbySharingService::ReceiveSurfaceState state,
      uint8_t vendor_id = kVendorId) {
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->RegisterReceiveSurface(
        transfer_callback, state,
        static_cast<Advertisement::BlockedVendorId>(vendor_id),
        [&](NearbySharingService::StatusCodes status_codes) {
          result = status_codes;
          notification.Notify();
        });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    return result;
  }

  NearbySharingService::StatusCodes UnregisterReceiveSurface(
      TransferUpdateCallback* transfer_callback) {
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->UnregisterReceiveSurface(
        transfer_callback, [&](NearbySharingService::StatusCodes status_codes) {
          result = status_codes;
          notification.Notify();
        });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    return result;
  }

  NearbySharingService::StatusCodes SendAttachments(
      int64_t share_target_id,
      std::unique_ptr<AttachmentContainer> attachment_container) {
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->SendAttachments(
        share_target_id, std::move(attachment_container),
        [&](NearbySharingService::StatusCodes status_codes) {
          result = status_codes;
          notification.Notify();
        });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    return result;
  }

  void Shutdown() {
    if (is_shutdown_) {
      return;
    }
    is_shutdown_ = true;
    NearbySharingService::StatusCodes result =
        NearbySharingService::StatusCodes::kError;
    absl::Notification notification;
    service_->Shutdown([&](NearbySharingService::StatusCodes status_codes) {
      result = status_codes;
      notification.Notify();
    });

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  }

  void SetUpForegroundReceiveSurface(
      NiceMock<MockTransferUpdateCallback>& callback) {
    NearbySharingService::StatusCodes result = RegisterReceiveSurface(
        &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
    EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
    EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  }

  void SetUpBackgroundReceiveSurface(
      NiceMock<MockTransferUpdateCallback>& callback) {
    NearbySharingService::StatusCodes result = RegisterReceiveSurface(
        &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
    EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
    EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  }

  void ProcessLatestPublicCertificateDecryption(size_t expected_num_calls,
                                                bool success,
                                                bool for_self_share = false,
                                                uint8_t vendor_id = 0) {
    // Ensure that all pending mojo messages are processed and the certificate
    // manager state is as expected up to this point.
    std::vector<
        FakeNearbyShareCertificateManager::GetDecryptedPublicCertificateCall>&
        calls = certificate_manager()->get_decrypted_public_certificate_calls();

    ASSERT_FALSE(calls.empty());
    EXPECT_EQ(calls.size(), expected_num_calls);
    EXPECT_EQ(GetNearbyShareTestEncryptedMetadataKey().salt(),
              calls.back().encrypted_metadata_key.salt());
    EXPECT_EQ(GetNearbyShareTestEncryptedMetadataKey().encrypted_key(),
              calls.back().encrypted_metadata_key.encrypted_key());

    if (success) {
      nearby::sharing::proto::PublicCertificate cert =
          GetNearbyShareTestPublicCertificate(
              DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS,
              GetNearbyShareTestNotBefore(), vendor_id);
      cert.set_for_self_share(for_self_share);
      std::move(calls.back().callback)(
          NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
              cert, GetNearbyShareTestEncryptedMetadataKey()));
    } else {
      std::move(calls.back().callback)(std::nullopt);
    }
    FlushTesting();
  }

  void SetUpKeyVerification(bool is_incoming,
                            PairedKeyResultFrame::Status status) {
    SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
    local_device_data_manager()->SetDeviceName(kDeviceName);

    Frame frame;
    frame.set_version(Frame::V1);
    V1Frame* v1_frame = frame.mutable_v1();
    v1_frame->set_type(V1Frame::PAIRED_KEY_ENCRYPTION);
    nearby::sharing::service::proto::PairedKeyEncryptionFrame*
        paired_key_encryption_frame =
            nearby::sharing::service::proto::PairedKeyEncryptionFrame::
                default_instance()
                    .New();
    paired_key_encryption_frame->set_signed_data(
        is_incoming ? std::string(GetIncomingConnectionSignedData().begin(),
                                  GetIncomingConnectionSignedData().end())
                    : std::string(GetOutgoingConnectionSignedData().begin(),
                                  GetOutgoingConnectionSignedData().end()));
    paired_key_encryption_frame->set_secret_id_hash(
        std::string(GetPrivateCertificateHashAuthToken().begin(),
                    GetPrivateCertificateHashAuthToken().end()));
    v1_frame->set_allocated_paired_key_encryption(paired_key_encryption_frame);
    std::vector<uint8_t> encryption_bytes(frame.ByteSizeLong());
    frame.SerializeToArray(encryption_bytes.data(), encryption_bytes.size());
    ReceiveMessageFromConnection(std::move(encryption_bytes));

    Frame result_frame;
    result_frame.set_version(Frame::V1);
    V1Frame* result_v1_frame = result_frame.mutable_v1();
    result_v1_frame->set_type(V1Frame::PAIRED_KEY_RESULT);
    PairedKeyResultFrame* paired_key_result_frame =
        result_v1_frame->mutable_paired_key_result();
    paired_key_result_frame->set_status(status);
    std::vector<uint8_t> result_bytes(result_frame.ByteSizeLong());
    result_frame.SerializeToArray(result_bytes.data(), result_bytes.size());
    ReceiveMessageFromConnection(std::move(result_bytes));
  }

  std::vector<uint8_t> CreateTestEndpointInfo(uint8_t vendor_id = kVendorId) {
    std::unique_ptr<Advertisement> advertisement = Advertisement::NewInstance(
        GetNearbyShareTestEncryptedMetadataKey().salt(),
        GetNearbyShareTestEncryptedMetadataKey().encrypted_key(), kDeviceType,
        kDeviceName, vendor_id);
    return advertisement->ToEndpointInfo();
  }

  void SetUpIntroductionFrameDecoder(bool return_empty_introduction_frame) {
    std::unique_ptr<Frame> frame;
    if (return_empty_introduction_frame) {
      frame = GetEmptyIntroductionFrame();
    } else {
      frame = GetValidIntroductionFrame();
    }
    std::vector<uint8_t> bytes(frame->ByteSizeLong());
    frame->SerializeToArray(bytes.data(), bytes.size());
    ReceiveMessageFromConnection(std::move(bytes));
  }

  void SendConnectionResponse(ConnectionResponseFrame::Status status) {
    std::unique_ptr<Frame> frame = GetConnectionResponseFrame(status);
    std::vector<uint8_t> bytes(frame->ByteSizeLong());
    frame->SerializeToArray(bytes.data(), bytes.size());
    ReceiveMessageFromConnection(std::move(bytes));
  }

  void SendCancel() {
    std::unique_ptr<Frame> frame = GetCancelFrame();
    std::vector<uint8_t> bytes(frame->ByteSizeLong());
    frame->SerializeToArray(bytes.data(), bytes.size());
    ReceiveMessageFromConnection(std::move(bytes));
  }

  int64_t SetUpIncomingConnection(
      NiceMock<MockTransferUpdateCallback>& callback, bool is_foreground = true,
      bool for_self_share = false) {
    fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                                GetToken());
    SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);

    int64_t share_target_id;
    SetLanConnected(true);
    absl::Notification notification;
    EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
        .WillOnce([&](const ShareTarget& incoming_share_target,
                      const AttachmentContainer& container,
                      const TransferMetadata& metadata) {
          EXPECT_FALSE(metadata.is_final_status());
          TransferMetadata::Status expected_status;

          if (for_self_share) {
            expected_status =
                TransferMetadata::Status::kAwaitingRemoteAcceptance;
          } else {
            expected_status =
                TransferMetadata::Status::kAwaitingLocalConfirmation;
          }

          EXPECT_EQ(metadata.status(), expected_status);
          share_target_id = incoming_share_target.id;
          notification.Notify();
        });

    SetUpKeyVerification(
        /*is_incoming=*/true, PairedKeyResultFrame::SUCCESS);
    if (is_foreground) {
      SetUpForegroundReceiveSurface(callback);
    } else {
      SetUpBackgroundReceiveSurface(callback);
    }
    EXPECT_CALL(*mock_app_info_, SetActiveFlag());
    StartIncomingConnection();
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true, for_self_share);
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
    return share_target_id;
  }

  void AcceptConnection(NiceMock<MockTransferUpdateCallback>& callback,
                        int64_t share_target_id,
                        absl::string_view endpoint_id) {
    // After accepting the transfer, we get another update of
    // kAwaitingRemoteAcceptance.
    EXPECT_CALL(callback,
                OnTransferUpdate(
                    testing::_, testing::_,
                    nearby::sharing::HasStatus(
                        TransferMetadata::Status::kAwaitingRemoteAcceptance)));
    absl::Notification accept_notification;
    service_->Accept(
        share_target_id,
        [&accept_notification](
            nearby::sharing::NearbySharingService::StatusCodes status_code) {
          EXPECT_EQ(status_code, NearbySharingServiceImpl::StatusCodes::kOk);
          accept_notification.Notify();
        });
    EXPECT_TRUE(
        accept_notification.WaitForNotificationWithTimeout(kWaitTimeout));
    EXPECT_TRUE(
        fake_nearby_connections_manager_->DidUpgradeBandwidth(endpoint_id));
  }

  int64_t SetUpOutgoingShareTarget(
      MockTransferUpdateCallback& transfer_callback,
      MockShareTargetDiscoveredCallback& discovery_callback) {
    SetUpKeyVerification(
        /*is_incoming=*/false, PairedKeyResultFrame::SUCCESS);

    fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                                GetToken());
    fake_nearby_connections_manager_->set_nearby_connection(connection_.get());
    return DiscoverShareTarget(transfer_callback, discovery_callback);
  }

  int64_t DiscoverShareTarget(
      MockTransferUpdateCallback& transfer_callback,
      MockShareTargetDiscoveredCallback& discovery_callback) {
    SetLanConnected(true);

    // Start discovering, to ensure a discovery listener is registered.
    EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                  SendSurfaceState::kForeground),
              NearbySharingService::StatusCodes::kOk);
    EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

    int64_t discovered_target_id;
    // Discover a new endpoint, with fields set up a valid certificate.
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
        .WillOnce([&discovered_target_id](ShareTarget share_target) {
          discovered_target_id = share_target.id;
        });

    auto endpoint_info = std::make_unique<DiscoveredEndpointInfo>(
        CreateTestEndpointInfo(), kServiceId);
    fake_nearby_connections_manager_->OnEndpointFound(kEndpointId,
                                                      std::move(endpoint_info));
    FlushTesting();
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true);
    return discovered_target_id;
  }

  std::unique_ptr<Frame> GetWrittenFrame() {
    EXPECT_TRUE(
        sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
    absl::MutexLock lock(connection_output_mutex_);
    std::unique_ptr<Frame> frame = std::move(frames_data_.front());
    frames_data_.pop();
    return frame;
  }

  PayloadInfo GetWrittenPayload() {
    EXPECT_TRUE(
        sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
    absl::MutexLock lock(connection_output_mutex_);
    PayloadInfo info = std::move(written_payloads_.front());
    written_payloads_.pop();
    return info;
  }

  bool ExpectPairedKeyEncryptionFrame() {
    std::unique_ptr<Frame> frame = GetWrittenFrame();
    if (!frame->has_v1()) {
      return false;
    }

    if (!frame->v1().has_paired_key_encryption()) {
      return false;
    }

    return true;
  }

  bool ExpectPairedKeyResultFrame() {
    std::unique_ptr<Frame> frame = GetWrittenFrame();
    if (!frame->has_v1()) {
      return false;
    }

    if (!frame->v1().has_paired_key_result()) {
      return false;
    }

    return true;
  }

  bool ExpectConnectionResponseFrame(ConnectionResponseFrame::Status status) {
    std::unique_ptr<Frame> frame = GetWrittenFrame();
    if (!frame->has_v1()) {
      return false;
    }

    if (!frame->v1().has_connection_response()) {
      return false;
    }

    if (status != frame->v1().connection_response().status()) {
      return false;
    }

    return true;
  }

  std::optional<IntroductionFrame> ExpectIntroductionFrame() {
    std::unique_ptr<Frame> frame = GetWrittenFrame();
    if (!frame->has_v1()) {
      return std::nullopt;
    }

    if (!frame->v1().has_introduction()) {
      return std::nullopt;
    }

    return frame->v1().introduction();
  }

  bool ExpectCancelFrame() {
    std::unique_ptr<Frame> frame = GetWrittenFrame();
    if (!frame->has_v1()) {
      return false;
    }

    if (frame->v1().type() != V1Frame::CANCEL) {
      return false;
    }

    return true;
  }

  // Optionally, |new_share_target| is updated with the ShareTargets sent to
  // OnTransferUpdate() calls.
  void ExpectTransferUpdates(
      MockTransferUpdateCallback& transfer_callback, int64_t share_target_id,
      const std::vector<TransferMetadata::Status>& updates,
      std::function<void()> callback) {
    expect_transfer_updates_count_ = 0;
    expect_transfer_updates_callback_ = std::move(callback);
    auto& expectation =
        EXPECT_CALL(transfer_callback, OnTransferUpdate).Times(updates.size());

    for (TransferMetadata::Status status : updates) {
      expectation.WillOnce(
          [this, share_target_id, status, update_size = updates.size()](
              const ShareTarget& share_target,
              const AttachmentContainer& container,
              const TransferMetadata& metadata) {
            EXPECT_EQ(share_target.id, share_target_id);
            EXPECT_EQ(metadata.status(), status);

            ++expect_transfer_updates_count_;
            if (expect_transfer_updates_count_ == update_size) {
              expect_transfer_updates_callback_();
            }
          });
    }
  }

  // Returns the modified ShareTarget received from a TransferUpdate.
  void SetUpOutgoingConnectionUntilAccept(
      MockTransferUpdateCallback& transfer_callback, int64_t share_target_id) {
    ExpectTransferUpdates(transfer_callback, share_target_id,
                          {TransferMetadata::Status::kConnecting,
                           TransferMetadata::Status::kAwaitingRemoteAcceptance},
                          [] {});

    absl::Notification send_notification;
    NearbySharingServiceImpl::StatusCodes send_result;
    EXPECT_CALL(*mock_app_info_, SetActiveFlag());
    service_->SendAttachments(
        share_target_id, CreateTextAttachments({kTextPayload}),
        [&](NearbySharingServiceImpl::StatusCodes status_codes) {
          send_result = status_codes;
          send_notification.Notify();
        });

    EXPECT_TRUE(
        send_notification.WaitForNotificationWithTimeout(kTaskWaitTimeout));
    EXPECT_EQ(send_result, NearbySharingServiceImpl::StatusCodes::kOk);

    FlushTesting();
    // Verify data sent to the remote device so far.
    if (!ExpectPairedKeyEncryptionFrame()) {
      return;
    }

    if (!ExpectPairedKeyResultFrame()) {
      return;
    }

    if (!ExpectIntroductionFrame().has_value()) {
      return;
    }
  }

  PayloadInfo AcceptAndSendPayload(
      MockTransferUpdateCallback& transfer_callback, int64_t share_target_id) {
    // We're now waiting for the remote device to respond with the accept
    // result.
    ExpectTransferUpdates(transfer_callback, share_target_id,
                          {TransferMetadata::Status::kInProgress}, [] {});

    // Kick off send process by accepting the transfer from the remote device.
    SendConnectionResponse(ConnectionResponseFrame::ACCEPT);
    PayloadInfo info = GetWrittenPayload();
    EXPECT_EQ(kTextPayload,
              std::string(info.payload->content.bytes_payload.bytes.begin(),
                          info.payload->content.bytes_payload.bytes.end()));
    return info;
  }

  void FinishOutgoingTransfer(MockTransferUpdateCallback& transfer_callback,
                              int64_t share_target_id, bool complete,
                              const PayloadInfo& info) {
    // Simulate a successful transfer via Nearby Connections.
    ExpectTransferUpdates(transfer_callback, share_target_id,
                          {TransferMetadata::Status::kInProgress,
                           complete ? TransferMetadata::Status::kComplete
                                    : TransferMetadata::Status::kFailed},
                          [] {});

    auto payload_transfer_update = std::make_unique<PayloadTransferUpdate>(
        info.payload->id, PayloadStatus::kSuccess,
        /*total_bytes=*/strlen(kTextPayload),
        /*bytes_transferred=*/strlen(kTextPayload));
    if (auto listener = info.listener.lock()) {
      listener->OnStatusUpdate(std::move(payload_transfer_update));
    }
    EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kWaitTimeout));
  }

  std::unique_ptr<Advertisement> GetCurrentAdvertisement() {
    auto endpoint_info =
        fake_nearby_connections_manager_->advertising_endpoint_info();
    if (!endpoint_info) return nullptr;

    return Advertisement::FromEndpointInfo(absl::MakeSpan(
        *fake_nearby_connections_manager_->advertising_endpoint_info()));
  }

  std::vector<uint8_t> CreateInvalidTestEndpointInfo() {
    std::unique_ptr<Advertisement> advertisement = Advertisement::NewInstance(
        GetNearbyShareTestEncryptedMetadataKey().salt(),
        GetNearbyShareTestEncryptedMetadataKey().encrypted_key(), kDeviceType,
        std::nullopt, kVendorId);
    return advertisement->ToEndpointInfo();
  }

  void FindInvalidEndpoint(absl::string_view endpoint_id) {
    fake_nearby_connections_manager_->OnEndpointFound(
        endpoint_id, std::make_unique<DiscoveredEndpointInfo>(
                         CreateInvalidTestEndpointInfo(), kServiceId));
    FlushTesting();
  }

  void FindEndpoint(absl::string_view endpoint_id) {
    FindEndpointWithVendorId(endpoint_id, kVendorId);
  }

  void FindEndpointWithVendorId(absl::string_view endpoint_id,
                                uint8_t vendor_id) {
    fake_nearby_connections_manager_->OnEndpointFound(
        endpoint_id, std::make_unique<DiscoveredEndpointInfo>(
                         CreateTestEndpointInfo(vendor_id), kServiceId));
    FlushTesting();
  }

  void LoseEndpoint(absl::string_view endpoint_id) {
    fake_nearby_connections_manager_->OnEndpointLost(endpoint_id);
    FlushTesting();
  }

  // This method sets up an incoming connection and performs the steps
  // required to simulate a successful incoming transfer.
  void SuccessfullyReceiveTransfer() {
    NiceMock<MockTransferUpdateCallback> callback;
    int64_t share_target_id = SetUpIncomingConnection(callback);
    ScopedReceiveSurface r(service_.get(), &callback);
    AcceptConnection(callback, share_target_id, kEndpointId);

    // Fail to accept again.
    service_->Accept(
        share_target_id,
        [&](NearbySharingServiceImpl::StatusCodes status_code) {
          EXPECT_EQ(status_code,
                    NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall);
        });

    fake_nearby_connections_manager_->SetIncomingPayload(
        kFilePayloadId, GetFilePayload(kFilePayloadId));
    EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
        .WillRepeatedly([&](const ShareTarget& share_target,
                            const AttachmentContainer& container,
                            TransferMetadata metadata) {
          EXPECT_FALSE(metadata.is_final_status());
          EXPECT_EQ(metadata.status(), TransferMetadata::Status::kInProgress);
        });

    absl::Notification block_notification;
    // Block the service thread so all PayloadTransferUpdate will be processed
    // together..
    sharing_service_task_runner_->PostTask([&block_notification]() {
      block_notification.WaitForNotificationWithTimeout(absl::Seconds(5));
    });
    for (int64_t id : GetValidIntroductionFramePayloadIds()) {
      // Update file payload at the end.
      if (id == kFilePayloadId) continue;

      fake_nearby_connections_manager_->SetIncomingPayload(
          id, GetTextPayload(id, kTextPayload));

      std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
          fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
              id);

      PayloadTransferUpdate payload_update =
          PayloadTransferUpdate(id, PayloadStatus::kSuccess,
                                /*total_bytes=*/kPayloadSize,
                                /*bytes_transferred=*/kPayloadSize);
      if (auto locked_listener = listener.lock()) {
        locked_listener->OnStatusUpdate(
            std::make_unique<PayloadTransferUpdate>(payload_update));
      }
    }
    block_notification.Notify();
    FlushTesting();

    std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
        fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
            kFilePayloadId);

    FilePath file_path;
    absl::Notification success_notification;
    EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
        .WillOnce([&](const ShareTarget& share_target,
                      const AttachmentContainer& container,
                      TransferMetadata metadata) {
          EXPECT_TRUE(metadata.is_final_status());
          EXPECT_EQ(metadata.status(), TransferMetadata::Status::kComplete);
          ASSERT_TRUE(container.HasAttachments());
          EXPECT_EQ(1u, container.GetFileAttachments().size());
          for (const FileAttachment& file : container.GetFileAttachments()) {
            EXPECT_TRUE(file.file_path());
            file_path = *file.file_path();
          }

          EXPECT_EQ(3u, container.GetTextAttachments().size());
          for (const TextAttachment& text : container.GetTextAttachments()) {
            EXPECT_EQ(text.text_body(), kTextPayload);
          }

          success_notification.Notify();
        });
    PayloadTransferUpdate payload =
        PayloadTransferUpdate(kFilePayloadId, PayloadStatus::kSuccess,
                              /*total_bytes=*/kPayloadSize,
                              /*bytes_transferred=*/kPayloadSize);
    if (auto locked_listener = listener.lock()) {
      locked_listener->OnStatusUpdate(
          std::make_unique<PayloadTransferUpdate>(payload));
    }
    FlushTesting();

    EXPECT_TRUE(
        success_notification.WaitForNotificationWithTimeout(kWaitTimeout));
    FlushTesting();
    EXPECT_FALSE(
        fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
            .has_value());
    // connection has been closed, destroy it like the real connections manager.
    connection_.reset();
    EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads());

    // Remove test file.
    Files::RemoveFile(file_path);
  }

  void FlushTesting() {
    absl::SleepFor(absl::Milliseconds(200));
    EXPECT_TRUE(
        sharing_service_task_runner_->SyncWithTimeout(absl::Milliseconds(200)));
  }

  void SetDiskSpace(size_t size) {
    fake_device_info_.SetAvailableDiskSpaceInBytes(
        Files::GetTemporaryDirectory(), size);
  }

  void ResetDiskSpace() { fake_device_info_.ResetDiskSpace(); }

 protected:
  FakeNearbyShareLocalDeviceDataManager* local_device_data_manager() {
    EXPECT_EQ(local_device_data_manager_factory_.instances().size(), 1u);
    return local_device_data_manager_factory_.instances().back();
  }

  FakeNearbyShareCertificateManager* certificate_manager() {
    EXPECT_EQ(certificate_manager_factory_.instances().size(), 1u);
    return certificate_manager_factory_.instances().back();
  }

  FakeAccountManager& account_manager() { return fake_account_manager_; }

  FilePath CreateTestFile(absl::string_view name,
                          const std::vector<uint8_t>& content) {
    FilePath path = Files::GetTemporaryDirectory().append(FilePath(name));
    std::ofstream file(path.GetPath(),
                       std::ios_base::out | std::ios_base::trunc);
    if (file.good()) {
      file.write(reinterpret_cast<const char*>(content.data()), content.size());
    }
    file.close();
    return path;
  }

  PreferenceManager& preference_manager() { return preference_manager_; }

  api::MockSharingPlatform mock_sharing_platform_;
  nearby::FakePreferenceManager preference_manager_;
  FakeAccountManager fake_account_manager_;
  FakeContext fake_context_;
  FakeDeviceInfo fake_device_info_;
  FakeNearbyConnectionsManager* fake_nearby_connections_manager_ = nullptr;
  FakeNearbyShareLocalDeviceDataManager::Factory
      local_device_data_manager_factory_;
  FakeNearbyShareContactManager* contact_manager_ = nullptr;
  FakeNearbyShareCertificateManager::Factory certificate_manager_factory_;
  std::unique_ptr<FakeNearbyFastInitiation::Factory>
      nearby_fast_initiation_factory_;
  std::unique_ptr<NearbyConnectionImpl> connection_;
  StrictMock<MockAppInfo>* mock_app_info_ = nullptr;
  std::unique_ptr<analytics::AnalyticsRecorder> analytics_recorder_;
  std::unique_ptr<NearbySharingServiceImpl> service_;
  int expect_transfer_updates_count_ = 0;
  std::function<void()> expect_transfer_updates_callback_;
  FakeTaskRunner* sharing_service_task_runner_ = nullptr;
  bool is_shutdown_ = false;
  absl::Mutex connection_output_mutex_;
  std::queue<std::unique_ptr<Frame>> frames_data_
      ABSL_GUARDED_BY(connection_output_mutex_);
  std::queue<PayloadInfo> written_payloads_
      ABSL_GUARDED_BY(connection_output_mutex_);
};

struct ValidSendSurfaceTestData {
  bool bluetooth_enabled;
  bool lan_connected;
} kValidSendSurfaceTestData[] = {
    // No network connection, only bluetooth available
    {true, false},
    // Wifi available
    {true, true},
};

class NearbySharingServiceImplValidSendTest
    : public NearbySharingServiceImplTest,
      public testing::WithParamInterface<ValidSendSurfaceTestData> {};

struct InvalidSendSurfaceTestData {
} kInvalidSendSurfaceTestData[] = {
    // Screen locked
    {/*screen_locked=*/},
    // No network connection and no bluetooth
    {/*screen_locked=*/},
    // 3G available and no bluetooth
    {/*screen_locked=*/},
    // Wi-Fi available and no bluetooth (invalid until Wi-Fi LAN is supported)
    {/*screen_locked=*/},
    // Ethernet available and no bluetooth (invalid until Wi-Fi LAN is
    // supported)
    {/*screen_locked=*/}};

using ResponseFrameStatus = ConnectionResponseFrame::Status;

struct SendFailureTestData {
  ResponseFrameStatus response_status;
  TransferMetadata::Status expected_status;
} kSendFailureTestData[] = {
    {service::proto::ConnectionResponseFrame::REJECT,
     TransferMetadata::Status::kRejected},
    {service::proto::ConnectionResponseFrame::NOT_ENOUGH_SPACE,
     TransferMetadata::Status::kNotEnoughSpace},
    {service::proto::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE,
     TransferMetadata::Status::kUnsupportedAttachmentType},
    {service::proto::ConnectionResponseFrame::TIMED_OUT,
     TransferMetadata::Status::kTimedOut},
    {service::proto::ConnectionResponseFrame::UNKNOWN,
     TransferMetadata::Status::kFailed},
};

class NearbySharingServiceImplSendFailureTest
    : public NearbySharingServiceImplTest,
      public testing::WithParamInterface<SendFailureTestData> {};

class TestObserver : public NearbySharingService::Observer {
 public:
  explicit TestObserver(NearbySharingService* service) : service_(service) {
    service_->AddObserver(this);
  }

  ~TestObserver() override {
    // Check if Shutdown has been called.
    if (service_ != nullptr) {
      service_->RemoveObserver(this);
    }
  }

  void OnHighVisibilityChanged(bool in_high_visibility) override {
    in_high_visibility_ = in_high_visibility;
  }

  void OnStartAdvertisingFailure() override {
    on_start_advertising_failure_called_ = true;
  }

  void OnBluetoothStatusChanged(AdapterState state) override {
    bluetooth_state_ = state;
  }

  void OnLanStatusChanged(AdapterState state) override { lan_state_ = state; }

  void OnCredentialError() override { credential_error_called_ = true; }

  bool in_high_visibility_ = false;
  bool on_start_advertising_failure_called_ = false;
  bool credential_error_called_ = false;
  NearbySharingService* service_;
  AdapterState bluetooth_state_ = AdapterState::INVALID;
  AdapterState lan_state_ = AdapterState::INVALID;
};

TEST_F(NearbySharingServiceImplTest, StartFastInitiationAdvertising) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 1);

  // Call RegisterSendSurface a second time and make sure StartAdvertising is
  // not called again.
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kInvalidArgument);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 1);
}

TEST_F(NearbySharingServiceImplTest, StartFastInitiationAdvertisingError) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  nearby_fast_initiation_factory_->GetNearbyFastInitiation()
      ->SetStartAdvertisingError(true);
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundStartFastInitiationAdvertisingError) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kBackground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 0);
}

TEST_F(NearbySharingServiceImplTest, StopFastInitiationAdvertising) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 1);
  EXPECT_EQ(UnregisterSendSurface(&transfer_callback),
            NearbySharingService::StatusCodes::kOk);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(),
            fast_initiation->StopAdvertisingCount());
}

TEST_F(NearbySharingServiceImplTest,
       StopFastInitiationAdvertising_BluetoothBecomesNotPresent) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  SetBluetoothIsPresent(false);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 1);
  // EXPECT_EQ(fast_initiation->StopAdvertisingCount(), 1);
}

TEST_F(NearbySharingServiceImplTest,
       StopFastInitiationAdvertising_BluetoothBecomesNotPowered) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  SetBluetoothIsPowered(false);
  EXPECT_EQ(fast_initiation->StartAdvertisingCount(), 1);
  EXPECT_EQ(fast_initiation->StopAdvertisingCount(), 1);
}

TEST_F(NearbySharingServiceImplTest, FastInitiationScanning_StartAndStop) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(true);

  EXPECT_EQ(fast_initiation->StartScanningCount(), 1);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 0);

  // Trigger a call to StopFastInitiationScanning().
  SetBluetoothIsPowered(false);
  EXPECT_EQ(fast_initiation->StartScanningCount(), 1);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 1);

  // Trigger a call to StartFastInitiationScanning().
  SetBluetoothIsPowered(true);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_EQ(fast_initiation->StartScanningCount(), 2);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 1);
}

TEST_F(NearbySharingServiceImplTest,
       FastInitiationScanning_PostTransferCooldown) {
  FakeNearbyFastInitiation* fast_initiation =
      nearby_fast_initiation_factory_->GetNearbyFastInitiation();
  SetLanConnected(false);

  // Make sure we started scanning once
  EXPECT_EQ(fast_initiation->StartScanningCount(), 1);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 0);

  SuccessfullyReceiveTransfer();

  // Make sure we stopped scanning and didn't restart... yet.
  EXPECT_EQ(fast_initiation->StartScanningCount(), 1);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 1);

  // Fast-forward 10s to pass through the cooldown period.
  FastForward(absl::Seconds(10));

  // Make sure we restarted Fast Initiation scanning.
  EXPECT_EQ(fast_initiation->StartScanningCount(), 2);
  EXPECT_EQ(fast_initiation->StopScanningCount(), 1);
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundRegisterSendSurfaceStartsDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundRegisterSendSurfaceTwiceKeepsDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kInvalidArgument);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest,
       RegisterSendSurfaceAlreadyReceivingNotDiscovering) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  AcceptConnection(callback, share_target_id, kEndpointId);
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  MockTransferUpdateCallback send_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&send_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kTransferAlreadyInProgress);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundRegisterSendSurfaceNotDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kBackground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest,
       DifferentSurfaceRegisterSendSurfaceTwiceKeepsDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kBackground),
            NearbySharingService::StatusCodes::kInvalidArgument);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest,
       RegisterSendSurfaceEndpointFoundDiscoveryCallbackNotified) {
  SetLanConnected(true);

  // Start discovering, to ensure a discovery listener is registered.
  MockTransferUpdateCallback transfer_callback;
  NiceMock<MockShareTargetDiscoveredCallback> discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  // Discover a new endpoint, with fields set up a valid certificate.
  EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
      .WillOnce([&](ShareTarget share_target) {
        EXPECT_FALSE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
      });
  fake_nearby_connections_manager_->OnEndpointFound(
      kEndpointId, std::make_unique<DiscoveredEndpointInfo>(
                       CreateTestEndpointInfo(), kServiceId));
  FlushTesting();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  // Register another send surface, which will automatically catch up
  // discovered endpoints.
  MockTransferUpdateCallback transfer_callback2;
  NiceMock<MockShareTargetDiscoveredCallback> discovery_callback2;
  EXPECT_CALL(discovery_callback2, OnShareTargetDiscovered)
      .WillOnce([&](ShareTarget share_target) {
        EXPECT_EQ(share_target.device_name, kDeviceName);
      });

  EXPECT_EQ(RegisterSendSurface(&transfer_callback2, &discovery_callback2,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s2(service_.get(), &transfer_callback2);

  // Shut down the service while the discovery callbacks are still in
  // scope. OnShareTargetLost() will be invoked during shutdown.
  Shutdown();
}

TEST_F(NearbySharingServiceImplTest, RegisterSendSurfaceEmptyCertificate) {
  SetLanConnected(true);

  // Start discovering, to ensure a discovery listener is registered.
  MockTransferUpdateCallback transfer_callback;
  NiceMock<MockShareTargetDiscoveredCallback> discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  // Discover a new endpoint, with fields set up a valid certificate.
  EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
      .WillOnce([](ShareTarget share_target) {
        EXPECT_FALSE(share_target.is_incoming);
        EXPECT_FALSE(share_target.is_known);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_FALSE(share_target.image_url);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_EQ(share_target.device_id, kEndpointId);
        EXPECT_FALSE(share_target.full_name);
      });
  fake_nearby_connections_manager_->OnEndpointFound(
      kEndpointId, std::make_unique<DiscoveredEndpointInfo>(
                       CreateTestEndpointInfo(), kServiceId));
  FlushTesting();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/false);
  // Register another send surface, which will automatically catch up
  // discovered endpoints.
  MockTransferUpdateCallback transfer_callback2;
  NiceMock<MockShareTargetDiscoveredCallback> discovery_callback2;
  EXPECT_CALL(discovery_callback2, OnShareTargetDiscovered)
      .WillOnce([](ShareTarget share_target) {
        EXPECT_EQ(share_target.device_name, kDeviceName);
      });

  EXPECT_EQ(RegisterSendSurface(&transfer_callback2, &discovery_callback2,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s2(service_.get(), &transfer_callback2);

  // Shut down the service while the discovery callbacks are still in scope.
  // OnShareTargetLost() will be invoked during shutdown.
  Shutdown();
}

TEST_P(NearbySharingServiceImplValidSendTest,
       RegisterSendSurfaceIsDiscovering) {
  SetBluetoothIsPresent(GetParam().bluetooth_enabled);
  SetLanConnected(GetParam().lan_connected);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  FlushTesting();
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

INSTANTIATE_TEST_SUITE_P(NearbySharingServiceImplTest,
                         NearbySharingServiceImplValidSendTest,
                         testing::ValuesIn(kValidSendSurfaceTestData));

TEST_F(NearbySharingServiceImplTest, UnregisterSendSurfaceStopsDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  EXPECT_EQ(UnregisterSendSurface(&transfer_callback),
            NearbySharingService::StatusCodes::kOk);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest,
       UnregisterSendSurfaceDifferentCallbackKeepDiscovering) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  MockTransferUpdateCallback transfer_callback2;
  MockShareTargetDiscoveredCallback discovery_callback2;
  EXPECT_EQ(UnregisterSendSurface(&transfer_callback2),
            NearbySharingService::StatusCodes::kError);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest, UnregisterSendSurfaceNeverRegistered) {
  SetLanConnected(true);

  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(UnregisterSendSurface(&transfer_callback),
            NearbySharingService::StatusCodes::kError);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundRegisterReceiveSurfaceIsAdvertisingAllContacts) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  ::nearby::AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);
  local_device_data_manager()->SetDeviceName(kDeviceName);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_EQ(fake_nearby_connections_manager_->advertising_power_level(),
            PowerLevel::kHighPower);
  ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
  std::unique_ptr<Advertisement> advertisement = GetCurrentAdvertisement();
  ASSERT_NE(advertisement, nullptr);
  EXPECT_EQ(advertisement->device_name(), std::nullopt);
  EXPECT_EQ(advertisement->device_type(), ShareTargetType::kLaptop);
  auto& test_metadata_key = GetNearbyShareTestEncryptedMetadataKey();
  EXPECT_EQ(test_metadata_key.salt(), advertisement->salt());
  EXPECT_EQ(test_metadata_key.encrypted_key(),
            advertisement->encrypted_metadata_key());
  account_manager().SetAccount(std::nullopt);
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundRegisterReceiveSurfaceIsAdvertisingNoOne) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE);
  local_device_data_manager()->SetDeviceName(kDeviceName);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_EQ(PowerLevel::kHighPower,
            fake_nearby_connections_manager_->advertising_power_level());
  ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
  std::unique_ptr<Advertisement> advertisement = GetCurrentAdvertisement();
  ASSERT_NE(advertisement, nullptr);
  EXPECT_EQ(advertisement->device_name(), std::nullopt);
  EXPECT_EQ(ShareTargetType::kLaptop, advertisement->device_type());
  // Expecting random metadata key.
  EXPECT_EQ(static_cast<size_t>(sharing::Advertisement::kSaltSize),
            advertisement->salt().size());
  EXPECT_EQ(static_cast<size_t>(
                sharing::Advertisement::kMetadataEncryptionKeyHashByteSize),
            advertisement->encrypted_metadata_key().size());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundRegisterReceiveSurfaceIsAdvertisingSelectedContacts) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS);
  ::nearby::AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_EQ(PowerLevel::kLowPower,
            fake_nearby_connections_manager_->advertising_power_level());
  ASSERT_TRUE(fake_nearby_connections_manager_->advertising_endpoint_info());
  std::unique_ptr<Advertisement> advertisement = GetCurrentAdvertisement();
  ASSERT_NE(advertisement, nullptr);
  EXPECT_FALSE(advertisement->device_name());
  EXPECT_EQ(ShareTargetType::kLaptop, advertisement->device_type());
  auto& test_metadata_key = GetNearbyShareTestEncryptedMetadataKey();
  EXPECT_EQ(test_metadata_key.salt(), advertisement->salt());
  EXPECT_EQ(test_metadata_key.encrypted_key(),
            advertisement->encrypted_metadata_key());
  account_manager().SetAccount(std::nullopt);
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceTwiceSameCallbackKeepAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  NearbySharingService::StatusCodes result2 = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result2, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceTwiceKeepAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  MockTransferUpdateCallback callback2;
  NearbySharingService::StatusCodes result2 = RegisterReceiveSurface(
      &callback2, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result2, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r2(service_.get(), &callback2);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       DataUsageChangedRegisterReceiveSurfaceRestartsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  preference_manager().SetInteger(
      prefs::kNearbySharingDataUsageName,
      static_cast<int>(DataUsage::OFFLINE_DATA_USAGE));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_EQ(DataUsage::OFFLINE_DATA_USAGE,
            fake_nearby_connections_manager_->advertising_data_usage());

  preference_manager().SetInteger(
      prefs::kNearbySharingDataUsageName,
      static_cast<int>(DataUsage::ONLINE_DATA_USAGE));
  FlushTesting();
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_EQ(DataUsage::ONLINE_DATA_USAGE,
            fake_nearby_connections_manager_->advertising_data_usage());
}

TEST_F(
    NearbySharingServiceImplTest,
    UnregisterForegroundReceiveSurfaceVisibilityAllContactsRestartAdvertising) {
  TestObserver observer(service_.get());
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();

  // Register both foreground and background receive surfaces
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &background_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &background_transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  MockTransferUpdateCallback foreground_transfer_callback;
  result = RegisterReceiveSurface(
      &foreground_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r2(service_.get(), &foreground_transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  // Unregister the foreground surface. Advertising is stopped and restarted
  // with low power. The service reports InHighVisibility until the
  // StopAdvertising callback is called.
  FakeNearbyConnectionsManager::ConnectionsCallback stop_advertising_callback =
      fake_nearby_connections_manager_->GetStopAdvertisingCallback();
  FakeNearbyConnectionsManager::ConnectionsCallback start_advertising_callback =
      fake_nearby_connections_manager_->GetStartAdvertisingCallback();
  result = UnregisterReceiveSurface(&foreground_transfer_callback);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(observer.in_high_visibility_);

  std::move(stop_advertising_callback)(ConnectionsStatus::kSuccess);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(observer.in_high_visibility_);

  std::move(start_advertising_callback)(ConnectionsStatus::kSuccess);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(observer.in_high_visibility_);
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceWithVendorId_StartAdvertisingVendorId) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_EVERYONE));
  FlushTesting();

  // Register background receive surface with vendor ID 1.
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &background_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kBackground,
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
  ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &background_transfer_callback);
  ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  auto endpoint_info =
      fake_nearby_connections_manager_->advertising_endpoint_info();
  auto advertisement = Advertisement::FromEndpointInfo(*endpoint_info);
  EXPECT_EQ(advertisement->vendor_id(),
            static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceWithVendorId_DoesNotAdvertiseInContacts) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();

  // Register background receive surface with vendor ID 1.
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &background_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kBackground,
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
  ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &background_transfer_callback);
  ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  auto endpoint_info =
      fake_nearby_connections_manager_->advertising_endpoint_info();
  auto advertisement = Advertisement::FromEndpointInfo(*endpoint_info);
  EXPECT_EQ(advertisement->vendor_id(),
            static_cast<uint8_t>(Advertisement::BlockedVendorId::kNone));
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceWithDifferentVendorIdIsBlocked) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();

  // Register background receive surface with vendor ID 1.
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &background_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kBackground,
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
  ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &background_transfer_callback);
  ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  // Register foreground receive surface with different vendor ID.
  MockTransferUpdateCallback foreground_transfer_callback;
  result = RegisterReceiveSurface(
      &foreground_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kForeground, /*vendor_id=*/2);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kInvalidArgument);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       RegisterReceiveSurfaceWithVendorId_OkWithBgNoVendorId) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_EVERYONE));
  FlushTesting();

  // Register background receive surface with vendor ID 0.
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &background_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kBackground,
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kNone));
  ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &background_transfer_callback);
  ASSERT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  // Register foreground receive surface with vendor ID 1.
  MockTransferUpdateCallback foreground_transfer_callback;
  result = RegisterReceiveSurface(
      &foreground_transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kForeground,
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r2(service_.get(), &foreground_transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  // Verify endpoint info is advertising the foreground surface.
  auto endpoint_info =
      fake_nearby_connections_manager_->advertising_endpoint_info();
  auto advertisement = Advertisement::FromEndpointInfo(*endpoint_info);
  EXPECT_EQ(advertisement->vendor_id(),
            static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
}

TEST_F(NearbySharingServiceImplTest,
       NoNetworkRegisterReceiveSurfaceIsAdvertising) {
  MockTransferUpdateCallback callback;
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  // Succeeds since bluetooth is present.
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, WifiRegisterReceiveSurfaceIsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       EthernetRegisterReceiveSurfaceIsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       ThreeGRegisterReceiveSurfaceIsAdvertising) {
  SetLanConnected(false);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  // Since bluetooth is on, connection still succeeds.
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       NoBluetoothWifiReceiveSurfaceIsAdvertising) {
  SetBluetoothIsPresent(false);
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       NoBluetoothEthernetReceiveSurfaceIsAdvertising) {
  SetBluetoothIsPresent(false);
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundReceiveSurfaceNoOneVisibilityIsAdvertising) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundReceiveSurfaceNoOneVisibilityNotAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_UNSPECIFIED));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundReceiveSurfaceVisibilityToNoOneStopsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS);
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_HIDDEN));
  FlushTesting();
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest, ValidateLoginStateWhenSettingVisibility) {
  absl::Notification set_visibility_notification;
  NearbySharingService::StatusCodes set_visibility_status;
  SetLanConnected(true);
  FlushTesting();
  service_->SetVisibility(
      DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, absl::ZeroDuration(),
      [&set_visibility_notification,
       &set_visibility_status](NearbySharingService::StatusCodes status) {
        set_visibility_status = status;
        set_visibility_notification.Notify();
      });
  // We should not have been able to set all contacts visibility because we are
  // not logged in.
  ASSERT_TRUE(
      set_visibility_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_EQ(set_visibility_status,
            NearbySharingService::StatusCodes::kInvalidArgument);
  // Create account.
  AccountManager::Account account;
  account.id = kTestAccountId;
  // Log in.
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  account_manager().NotifyLogin(kTestAccountId);
  // We are now logged in, so we should be able to set all contacts visibility.
  absl::Notification set_visibility_notification2;
  NearbySharingService::StatusCodes set_visibility_status2;
  service_->SetVisibility(
      DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS, absl::ZeroDuration(),
      [&set_visibility_notification2,
       &set_visibility_status2](NearbySharingService::StatusCodes status) {
        set_visibility_status2 = status;
        set_visibility_notification2.Notify();
      });
  ASSERT_TRUE(set_visibility_notification2.WaitForNotificationWithTimeout(
      kWaitTimeout));
  EXPECT_EQ(set_visibility_status2, NearbySharingService::StatusCodes::kOk);
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundReceiveSurfaceVisibilityToAllContactsStartsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_UNSPECIFIED);
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());

  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  FlushTesting();
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundReceiveSurfaceSelectedContactsVisibilityIsAdvertising) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundReceiveSurfaceSelectedContactsVisibilityIsAdvertising) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_SELECTED_CONTACTS));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       ForegroundReceiveSurfaceAllContactsVisibilityIsAdvertising) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       BackgroundReceiveSurfaceAllContactsVisibilityNotAdvertising) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, UnregisterReceiveSurfaceStopsAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  NearbySharingService::StatusCodes result2 =
      UnregisterReceiveSurface(&callback);
  EXPECT_EQ(result2, NearbySharingService::StatusCodes::kOk);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest,
       UnregisterReceiveSurfaceDifferentCallbackKeepAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());

  MockTransferUpdateCallback callback2;
  NearbySharingService::StatusCodes result2 =
      UnregisterReceiveSurface(&callback2);
  EXPECT_EQ(result2, NearbySharingService::StatusCodes::kOk);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, UnregisterReceiveSurfaceNeverRegistered) {
  SetLanConnected(true);

  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result =
      UnregisterReceiveSurface(&callback);
  // This is no longer considered an error condition.
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, IncomingConnectionClosedAfterShutdown) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .Times(0);

  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  Shutdown();

  StartIncomingConnection();

  sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout);
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionClosedBeforeCertDecryption) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  NiceMock<MockTransferUpdateCallback> callback;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(TransferMetadata::Status::kFailed, metadata.status());
      });

  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  sharing_service_task_runner_->PostTask([this]() {
    fake_nearby_connections_manager_->Disconnect(kEndpointId);
    // FakeNearbyConnectionsManager does not delete the connection on close.
    connection_.reset();
  });
  sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout);
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionClosedReadingIntroduction) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(TransferMetadata::Status::kFailed, metadata.status());
      });

  SetUpKeyVerification(/*is_incoming=*/true,
                       service::proto::PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  sharing_service_task_runner_->PostTask([this]() {
    fake_nearby_connections_manager_->Disconnect(kEndpointId);
    // FakeNearbyConnectionsManager does not delete the connection on close.
    connection_.reset();
  });
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, IncomingConnectionEmptyIntroductionFrame) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/true);

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(),
                  TransferMetadata::Status::kUnsupportedAttachmentType);
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_FALSE(container.HasAttachments());
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
      });

  SetUpKeyVerification(/*is_incoming=*/true,
                       service::proto::PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  // Check data written to connection_.
  ASSERT_TRUE(ExpectPairedKeyEncryptionFrame());
  ASSERT_TRUE(ExpectPairedKeyResultFrame());
  ASSERT_TRUE(ExpectConnectionResponseFrame(
      service::proto::ConnectionResponseFrame::UNSUPPORTED_ATTACHMENT_TYPE));
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionValidIntroductionFrameInvalidCertificate) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;

  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_FALSE(metadata.is_final_status());
        EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
                  metadata.status());
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_FALSE(share_target.is_known);
        EXPECT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetTextAttachments().size(), 3u);
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_FALSE(share_target.image_url);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_EQ(share_target.device_id, kEndpointId);
        EXPECT_FALSE(share_target.full_name);
      });

  SetUpKeyVerification(/*is_incoming=*/true,
                       service::proto::PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/false);
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, IncomingConnectionTimedOut) {
  NiceMock<MockTransferUpdateCallback> callback;
  SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kTimedOut);
      });

  FastForward(kReadResponseFrameTimeout);

  // Waits for delay to close connection.
  FastForward(kIncomingRejectionDelay);
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionClosedWaitingLocalConfirmation) {
  NiceMock<MockTransferUpdateCallback> callback;
  SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kFailed);
      });

  sharing_service_task_runner_->PostTask([this]() {
    fake_nearby_connections_manager_->Disconnect(kEndpointId);
    // FakeNearbyConnectionsManager does not delete the connection on close.
    connection_.reset();
  });
  sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout);
}

TEST_F(NearbySharingServiceImplTest, IncomingConnectionOutOfStorage) {
  SetDiskSpace(kFreeDiskSpace);
  preference_manager().SetString(
      prefs::kNearbySharingCustomSavePath,
      fake_device_info_.GetDownloadPath().ToString());
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  // Set a huge file size in introduction frame to go out of storage.
  Frame frame;
  frame.set_version(Frame::V1);
  V1Frame* v1_frame = frame.mutable_v1();
  v1_frame->set_type(V1Frame::INTRODUCTION);
  IntroductionFrame* introduction_frame = v1_frame->mutable_introduction();
  nearby::sharing::service::proto::FileMetadata* file_metadata =
      introduction_frame->add_file_metadata();
  file_metadata->set_name("name");
  file_metadata->set_type(nearby::sharing::service::proto::FileMetadata::AUDIO);
  file_metadata->set_payload_id(1);
  file_metadata->set_size(kFreeDiskSpace + 1);
  file_metadata->set_mime_type("mime type");
  file_metadata->set_id(123);
  std::vector<uint8_t> bytes(frame.ByteSizeLong());
  frame.SerializeToArray(bytes.data(), bytes.size());
  ReceiveMessageFromConnection(std::move(bytes));

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetTextAttachments().size(), 0u);
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kNotEnoughSpace);
      });

  SetUpKeyVerification(
      /*is_incoming=*/true, PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  ResetDiskSpace();
}

TEST_F(NearbySharingServiceImplTest, IncomingConnectionFileSizeOverflow) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  // Set file size sum huge to check for overflow.
  Frame frame;
  frame.set_version(Frame::V1);
  V1Frame* v1_frame = frame.mutable_v1();
  v1_frame->set_type(V1Frame::INTRODUCTION);
  IntroductionFrame* introduction_frame = v1_frame->mutable_introduction();
  nearby::sharing::service::proto::FileMetadata* file_metadata =
      introduction_frame->add_file_metadata();
  file_metadata->set_name("name_1");
  file_metadata->set_type(nearby::sharing::service::proto::FileMetadata::AUDIO);
  file_metadata->set_payload_id(1);
  file_metadata->set_size(std::numeric_limits<int64_t>::max());
  file_metadata->set_mime_type("mime type");
  file_metadata->set_id(123);
  nearby::sharing::service::proto::FileMetadata* file2_metadata =
      introduction_frame->add_file_metadata();
  file2_metadata->set_name("name_2");
  file2_metadata->set_type(
      nearby::sharing::service::proto::FileMetadata::VIDEO);
  file2_metadata->set_payload_id(2);
  file2_metadata->set_size(100);
  file2_metadata->set_mime_type("mime type");
  file2_metadata->set_id(124);
  std::vector<uint8_t> bytes(frame.ByteSizeLong());
  frame.SerializeToArray(bytes.data(), bytes.size());
  ReceiveMessageFromConnection(std::move(bytes));

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;

  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kNotEnoughSpace);
      });

  SetUpKeyVerification(
      /*is_incoming=*/true, PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionValidIntroductionFrameValidCertificate) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  absl::Notification notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&notification](const ShareTarget& share_target,
                                const AttachmentContainer& container,
                                TransferMetadata metadata) {
        EXPECT_FALSE(metadata.is_final_status());
        EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
                  metadata.status());
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetTextAttachments().size(), 3u);
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
        EXPECT_FALSE(share_target.for_self_share);
        EXPECT_FALSE(metadata.is_self_share());
        EXPECT_TRUE(metadata.token().has_value());
        notification.Notify();
      });

  SetUpKeyVerification(/*is_incoming=*/true, PairedKeyResultFrame::SUCCESS);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, AcceptInvalidShareTarget) {
  absl::Notification notification;
  service_->Accept(
      98765L, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code,
                  NearbySharingServiceImpl::StatusCodes::kInvalidArgument);
        notification.Notify();
      });

  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, AcceptValidShareTarget) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  AcceptConnection(callback, share_target_id, kEndpointId);

  // Check data written to connection_.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  EXPECT_TRUE(ExpectConnectionResponseFrame(
      service::proto::ConnectionResponseFrame::ACCEPT));

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, AcceptValidShareTargetPayloadSuccessful) {
  SuccessfullyReceiveTransfer();
}

TEST_F(NearbySharingServiceImplTest,
       AcceptValidShareTargetPayloadSuccessfulIncomingPayloadNotFound) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  AcceptConnection(callback, share_target_id, kEndpointId);

  fake_nearby_connections_manager_->SetIncomingPayload(
      kFilePayloadId, GetFilePayload(kFilePayloadId));

  for (int64_t id : GetValidIntroductionFramePayloadIds()) {
    // Update file payload at the end.
    if (id == kFilePayloadId) continue;

    // Deliberately not calling SetIncomingPayload() for text payloads to check
    // for failure condition.

    absl::Notification progress_notification;
    EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
        .WillOnce([&](const ShareTarget& share_target,
                      const AttachmentContainer& container,
                      TransferMetadata metadata) {
          EXPECT_FALSE(metadata.is_final_status());
          EXPECT_EQ(metadata.status(), TransferMetadata::Status::kInProgress);
          progress_notification.Notify();
        });

    std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
        fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
            id);
    ASSERT_FALSE(listener.expired());

    auto payload = std::make_unique<PayloadTransferUpdate>(
        id, PayloadStatus::kSuccess,
        /*total_bytes=*/kPayloadSize,
        /*bytes_transferred=*/kPayloadSize);
    if (auto locked_listener = listener.lock()) {
      locked_listener->OnStatusUpdate(std::move(payload));
    }
    FlushTesting();
    EXPECT_TRUE(
        progress_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }

  absl::Notification success_notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(),
                  TransferMetadata::Status::kIncompletePayloads);
        ASSERT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        const FileAttachment& file = container.GetFileAttachments()[0];
        EXPECT_FALSE(file.file_path());
        success_notification.Notify();
      });

  std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
      fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
          kFilePayloadId);
  ASSERT_FALSE(listener.expired());

  auto payload = std::make_unique<PayloadTransferUpdate>(
      kFilePayloadId, PayloadStatus::kSuccess,
      /*total_bytes=*/kPayloadSize,
      /*bytes_transferred=*/kPayloadSize);
  if (auto locked_listener = listener.lock()) {
    locked_listener->OnStatusUpdate(std::move(payload));
  }
  EXPECT_TRUE(
      success_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  FlushTesting();
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads());

  // File deletion runs in a ThreadPool.
  EXPECT_TRUE(
      sharing_service_task_runner_->SyncWithTimeout(absl::Milliseconds(200)));
}

TEST_F(NearbySharingServiceImplTest, AcceptValidShareTargetPayloadFailed) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  AcceptConnection(callback, share_target_id, kEndpointId);

  absl::Notification failure_notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kFailed);
        ASSERT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        const FileAttachment& file = container.GetFileAttachments()[0];
        EXPECT_FALSE(file.file_path());
        failure_notification.Notify();
      });

  std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
      fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
          kFilePayloadId);
  ASSERT_FALSE(listener.expired());

  auto payload = std::make_unique<PayloadTransferUpdate>(
      kFilePayloadId, PayloadStatus::kFailure,
      /*total_bytes=*/kPayloadSize,
      /*bytes_transferred=*/kPayloadSize);
  if (auto locked_listener = listener.lock()) {
    locked_listener->OnStatusUpdate(std::move(payload));
  }

  EXPECT_TRUE(
      failure_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  FlushTesting();
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads());

  // File deletion runs in a ThreadPool.
  EXPECT_TRUE(
      sharing_service_task_runner_->SyncWithTimeout(absl::Milliseconds(200)));
}

TEST_F(NearbySharingServiceImplTest, AcceptValidShareTargetPayloadCancelled) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  AcceptConnection(callback, share_target_id, kEndpointId);

  absl::Notification failure_notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kCancelled);
        ASSERT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        const FileAttachment& file = container.GetFileAttachments()[0];
        EXPECT_FALSE(file.file_path());
        failure_notification.Notify();
      });

  std::weak_ptr<NearbyConnectionsManager::PayloadStatusListener> listener =
      fake_nearby_connections_manager_->GetRegisteredPayloadStatusListener(
          kFilePayloadId);
  ASSERT_FALSE(listener.expired());

  auto payload = std::make_unique<PayloadTransferUpdate>(
      kFilePayloadId, PayloadStatus::kCanceled,
      /*total_bytes=*/kPayloadSize,
      /*bytes_transferred=*/kPayloadSize);
  if (auto locked_listener = listener.lock()) {
    locked_listener->OnStatusUpdate(std::move(payload));
  }
  EXPECT_TRUE(
      failure_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_FALSE(fake_nearby_connections_manager_->has_incoming_payloads());

  // File deletion runs in a ThreadPool.
  EXPECT_TRUE(
      sharing_service_task_runner_->SyncWithTimeout(absl::Milliseconds(200)));
}

TEST_F(NearbySharingServiceImplTest, RejectInvalidShareTarget) {
  absl::Notification notification;
  service_->Reject(
      98456L, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code,
                  NearbySharingServiceImpl::StatusCodes::kInvalidArgument);
        notification.Notify();
      });

  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, RejectValidShareTarget) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id = SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  absl::Notification notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([](const ShareTarget& share_target,
                   const AttachmentContainer& container,
                   TransferMetadata metadata) {
        EXPECT_TRUE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kRejected);
      });

  service_->Reject(
      share_target_id, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code, NearbySharingServiceImpl::StatusCodes::kOk);
        notification.Notify();
      });

  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Check data written to connection_.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  EXPECT_TRUE(ExpectConnectionResponseFrame(ConnectionResponseFrame::REJECT));

  FastForward(kIncomingRejectionDelay + kDelta);
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionKeyVerificationRunnerStatusUnable) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  absl::Notification notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_FALSE(metadata.is_final_status());
        EXPECT_EQ(metadata.status(),
                  TransferMetadata::Status::kAwaitingLocalConfirmation);
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetTextAttachments().size(), 3u);
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);
        EXPECT_EQ(metadata.token(), kFourDigitToken);
        notification.Notify();
      });

  SetUpKeyVerification(/*is_incoming=*/true, PairedKeyResultFrame::UNABLE);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionKeyVerificationRunnerStatusUnableLowPower) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  SetUpIntroductionFrameDecoder(/*return_empty_introduction_frame=*/false);

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;
  absl::Notification notification;
  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_FALSE(metadata.is_final_status());
        EXPECT_EQ(TransferMetadata::Status::kAwaitingLocalConfirmation,
                  metadata.status());
        EXPECT_TRUE(share_target.is_incoming);
        EXPECT_TRUE(share_target.is_known);
        EXPECT_TRUE(container.HasAttachments());
        EXPECT_EQ(container.GetTextAttachments().size(), 3u);
        EXPECT_EQ(container.GetFileAttachments().size(), 1u);
        EXPECT_EQ(share_target.device_name, kDeviceName);
        EXPECT_EQ(share_target.type, kDeviceType);
        EXPECT_NE(share_target.device_id, kEndpointId);
        EXPECT_EQ(share_target.full_name, kTestMetadataFullName);

        EXPECT_EQ(kFourDigitToken, metadata.token());
        notification.Notify();
      });

  SetUpKeyVerification(/*is_incoming=*/true, PairedKeyResultFrame::UNABLE);

  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionKeyVerificationRunnerStatusFail) {
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());

  SetLanConnected(true);
  NiceMock<MockTransferUpdateCallback> callback;

  SetUpKeyVerification(/*is_incoming=*/true, PairedKeyResultFrame::FAIL);
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  // Ensures that introduction is never received for failed key verification.
  std::string intro = "introduction_frame";
  std::vector<uint8_t> bytes(intro.begin(), intro.end());
  ReceiveMessageFromConnection(std::move(bytes));
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  EXPECT_CALL(callback,
              OnTransferUpdate(
                  testing::_, testing::_,
                  nearby::sharing::HasStatus(
                      TransferMetadata::Status::kDeviceAuthenticationFailed)));
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);

  // Ensure that the messages sent by ProcessLatestPublicCertificateDecryption
  // are processed prior to checking if connection is closed.
  EXPECT_TRUE(
      sharing_service_task_runner_->SyncWithTimeout(absl::Milliseconds(200)));
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       IncomingConnectionEmptyAuthTokenKeyVerificationRunnerStatusFail) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_EVERYONE);
  NiceMock<MockTransferUpdateCallback> callback;

  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  // Ensures that introduction is never received for empty auth token.
  std::string intro = "introduction_frame";
  std::vector<uint8_t> bytes(intro.begin(), intro.end());
  ReceiveMessageFromConnection(std::move(bytes));
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  StartIncomingConnection();
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/true);

  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, RegisterReceiveSurfaceAlreadyReceiving) {
  NiceMock<MockTransferUpdateCallback> callback;
  SetUpIncomingConnection(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  EXPECT_EQ(
      RegisterReceiveSurface(
          &callback, NearbySharingService::ReceiveSurfaceState::kForeground),
      NearbySharingService::StatusCodes::kOk);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest, RegisterReceiveSurfaceWhileDiscovering) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &transfer_callback);
}

TEST_F(NearbySharingServiceImplTest, SendAttachmentsWithoutAttachments) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  EXPECT_EQ(SendAttachments(target_id, /*attachment_container=*/nullptr),
            NearbySharingServiceImpl::StatusCodes::kInvalidArgument);
}

TEST_F(NearbySharingServiceImplTest, RegisterReceiveSurfaceWhileSending) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &transfer_callback,
      NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &transfer_callback);
}

TEST_F(NearbySharingServiceImplTest, SendTextAlreadySending) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());
  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // We're now in the sending state, try to send again should fail
  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall);
}

TEST_F(NearbySharingServiceImplTest, SendTextWithoutScanning) {
  EXPECT_EQ(SendAttachments(325626L, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall);
}

TEST_F(NearbySharingServiceImplTest, SendTextUnknownTarget) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  EXPECT_EQ(SendAttachments(12345L, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kInvalidArgument);
}

TEST_F(NearbySharingServiceImplTest, SendTextFailedCreateEndpointInfo) {
  // Set name with too many characters.
  local_device_data_manager()->SetDeviceName(std::string(300, 'a'));

  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kError);
}

TEST_F(NearbySharingServiceImplTest, SendTextFailedToConnect) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  // Call DiscoverShareTarget() instead of SetUpOutgoingShareTarget() as we want
  // to fail before key verification is done.
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kFailed},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, SendTextFailedKeyVerification) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kDeviceAuthenticationFailed},
                        [&]() { notification.Notify(); });

  SetUpKeyVerification(/*is_incoming=*/false, PairedKeyResultFrame::FAIL);
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  fake_nearby_connections_manager_->set_nearby_connection(connection_.get());
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, SendTextUnableToVerifyKey) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });

  SetUpKeyVerification(/*is_incoming=*/false, PairedKeyResultFrame::UNABLE);
  fake_nearby_connections_manager_->SetRawAuthenticationToken(kEndpointId,
                                                              GetToken());
  fake_nearby_connections_manager_->set_nearby_connection(connection_.get());
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

INSTANTIATE_TEST_SUITE_P(NearbySharingServiceImplSendFailureTest,
                         NearbySharingServiceImplSendFailureTest,
                         testing::ValuesIn(kSendFailureTestData));

TEST_P(NearbySharingServiceImplSendFailureTest, SendTextRemoteFailure) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Verify data sent to the remote device so far.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  EXPECT_TRUE(ExpectIntroductionFrame().has_value());

  // We're now waiting for the remote device to respond with the accept
  absl::Notification reject_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {GetParam().expected_status},
                        [&]() { reject_notification.Notify(); });

  // Cancel the transfer by rejecting it.
  SendConnectionResponse(GetParam().response_status);
  EXPECT_TRUE(reject_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, SendFileWithEmptyPath) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      DiscoverShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  EXPECT_EQ(SendAttachments(target_id, CreateFileAttachments({FilePath{""}})),
            NearbySharingServiceImpl::StatusCodes::kInvalidArgument);
}

TEST_P(NearbySharingServiceImplSendFailureTest, SendFilesRemoteFailure) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  std::vector<uint8_t> test_data = {'T', 'e', 's', 't'};
  FilePath path = CreateTestFile("text.txt", test_data);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateFileAttachments({path})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Verify data sent to the remote device so far.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  EXPECT_TRUE(ExpectIntroductionFrame().has_value());

  // We're now waiting for the remote device to respond with the accept
  absl::Notification reject_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {GetParam().expected_status},
                        [&]() { reject_notification.Notify(); });

  // Cancel the transfer by rejecting it.
  SendConnectionResponse(GetParam().response_status);
  EXPECT_TRUE(reject_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, SendTextDisconnectTimeout) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateTextAttachments({kTextPayload})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Verify data sent to the remote device so far.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  std::optional<IntroductionFrame> intro = ExpectIntroductionFrame();

  ASSERT_TRUE(intro.has_value());
  ASSERT_EQ(intro->text_metadata_size(), 1);
  auto meta = intro->text_metadata(0);

  EXPECT_EQ(meta.text_title(), kTextPayload);
  EXPECT_EQ(static_cast<size_t>(meta.size()), strlen(kTextPayload));
  EXPECT_EQ(meta.type(), TextMetadata::TEXT);

  ASSERT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  std::unique_ptr<Advertisement> advertisement =
      Advertisement::FromEndpointInfo(absl::Span<const uint8_t>(
          *fake_nearby_connections_manager_->connection_endpoint_info(
              kEndpointId)));
  ASSERT_TRUE(advertisement);
  EXPECT_EQ(advertisement->device_name(), kDeviceName);
  EXPECT_EQ(advertisement->device_type(), ShareTargetType::kLaptop);
  auto& test_metadata_key = GetNearbyShareTestEncryptedMetadataKey();
  EXPECT_EQ(advertisement->salt(), test_metadata_key.salt());
  EXPECT_EQ(advertisement->encrypted_metadata_key(),
            test_metadata_key.encrypted_key());

  PayloadInfo info = AcceptAndSendPayload(transfer_callback, target_id);
  FinishOutgoingTransfer(transfer_callback, target_id, /*complete=*/false,
                         info);

  // We should not have called disconnect yet as we want to wait for 1 minute to
  // make sure all outgoing packets have been sent properly.
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  // Forward time until we send the disconnect request to Nearby
  FastForward(kOutgoingDisconnectionDelay);

  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  // FakeNearbyConnectionsManager does not destroy the connection.
  sharing_service_task_runner_->PostTask([this]() { connection_.reset(); });
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  account_manager().SetAccount(std::nullopt);
}

TEST_F(NearbySharingServiceImplTest, SendTextSuccessClosedConnection) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  SetUpOutgoingConnectionUntilAccept(transfer_callback, target_id);
  PayloadInfo info = AcceptAndSendPayload(transfer_callback, target_id);
  FinishOutgoingTransfer(transfer_callback, target_id, /*complete=*/true, info);

  // We should not have called disconnect yet as we want to wait for 1 minute
  // to make sure all outgoing packets have been sent properly.
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  // Call disconnect on the connection early before the timeout has passed.
  sharing_service_task_runner_->PostTask([this]() {
    fake_nearby_connections_manager_->Disconnect(kEndpointId);
    // FakeNearbyConnectionsManager does not destroy the connection.
    connection_.reset();
  });
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  // Make sure the scheduled disconnect callback does nothing.
  FastForward(kOutgoingDisconnectionDelay);
}

TEST_F(NearbySharingServiceImplTest, SendFilesSuccess) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  std::vector<uint8_t> test_data = {'T', 'e', 's', 't'};
  std::string file_name = "test.txt";
  FilePath path = CreateTestFile(file_name, test_data);

  absl::Notification introduction_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { introduction_notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateFileAttachments({path})),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(
      introduction_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Verify data sent to the remote device so far.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  auto intro = ExpectIntroductionFrame();
  ASSERT_TRUE(intro.has_value());
  ASSERT_EQ(intro->file_metadata_size(), 1);
  auto meta = intro->file_metadata(0);

  EXPECT_EQ(meta.name(), file_name);
  EXPECT_EQ(meta.mime_type(), "text/plain");
  EXPECT_EQ(test_data.size(), static_cast<size_t>(meta.size()));
  EXPECT_EQ(meta.type(), FileMetadata::UNKNOWN);

  // We're now waiting for the remote device to respond with the accept
  // result.
  absl::Notification accept_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kInProgress},
                        [&]() { accept_notification.Notify(); });

  // Kick off send process by accepting the transfer from the remote device.
  SendConnectionResponse(ConnectionResponseFrame::ACCEPT);

  EXPECT_TRUE(accept_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Expect the file payload to be sent in the end.
  PayloadInfo info = GetWrittenPayload();
  ASSERT_TRUE(info.payload->content.is_file());
  FilePath file = info.payload->content.file_payload.file.path;
  ASSERT_TRUE(Files::FileExists(file));
}

TEST_F(NearbySharingServiceImplTest, SendWifiCredentialsSuccess) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);

  absl::Notification introduction_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kConnecting,
                         TransferMetadata::Status::kAwaitingRemoteAcceptance},
                        [&]() { introduction_notification.Notify(); });
  EXPECT_CALL(*mock_app_info_, SetActiveFlag());

  EXPECT_EQ(SendAttachments(target_id, CreateWifiCredentialAttachments(
                                           "GoogleGuest", "password")),
            NearbySharingServiceImpl::StatusCodes::kOk);
  EXPECT_TRUE(
      introduction_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Verify data sent to the remote device so far.
  EXPECT_TRUE(ExpectPairedKeyEncryptionFrame());
  EXPECT_TRUE(ExpectPairedKeyResultFrame());
  std::optional<IntroductionFrame> intro = ExpectIntroductionFrame();

  ASSERT_TRUE(intro.has_value());
  ASSERT_EQ(intro->wifi_credentials_metadata_size(), 1);
  auto meta = intro->wifi_credentials_metadata(0);

  EXPECT_EQ(meta.ssid(), "GoogleGuest");
  EXPECT_EQ(meta.security_type(),
            service::proto::WifiCredentialsMetadata::WPA_PSK);

  // We're now waiting for the remote device to respond with the accept
  // result.
  absl::Notification accept_notification;
  ExpectTransferUpdates(transfer_callback, target_id,
                        {TransferMetadata::Status::kInProgress},
                        [&]() { accept_notification.Notify(); });

  // Kick off send process by accepting the transfer from the remote device.
  SendConnectionResponse(ConnectionResponseFrame::ACCEPT);

  EXPECT_TRUE(accept_notification.WaitForNotificationWithTimeout(kWaitTimeout));

  // Expect the wifi credential payload to be sent in the end.
  PayloadInfo info = GetWrittenPayload();
  ASSERT_TRUE(info.payload->content.is_bytes());
  std::vector<uint8_t> bytes = info.payload->content.bytes_payload.bytes;
  nearby::sharing::service::proto::WifiCredentials wifi_credentials;
  ASSERT_TRUE(wifi_credentials.ParseFromArray(bytes.data(), bytes.size()));
  EXPECT_EQ(wifi_credentials.password(), "password");
  EXPECT_FALSE(wifi_credentials.hidden_ssid());
}

TEST_F(NearbySharingServiceImplTest, CancelSenderInitiator) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  SetUpOutgoingConnectionUntilAccept(transfer_callback, target_id);
  PayloadInfo info = AcceptAndSendPayload(transfer_callback, target_id);

  // After we stop scanning, we check back in after kInvalidateDelay
  // milliseconds to make sure that we stopped in order to send a file and
  // not because the user left the page. We have to fast-forward here.
  // otherwise, we will hit this callback when trying to fast-forward by
  // kInitiatorCancelDelay below.
  FastForward(kInvalidateDelay);

  absl::Notification notification;
  EXPECT_CALL(transfer_callback,
              OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_EQ(share_target.id, target_id);
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kCancelled);
      });
  EXPECT_FALSE(
      fake_nearby_connections_manager_->WasPayloadCanceled(info.payload->id));
  // The initiator of the cancellation explicitly calls Cancel().
  service_->Cancel(
      target_id, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code, NearbySharingServiceImpl::StatusCodes::kOk);
        notification.Notify();
      });
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(
      fake_nearby_connections_manager_->WasPayloadCanceled(info.payload->id));

  // After the TransferMetadata::Status::kCancelled update, we expect other
  // classes to unregister the send surface.
  UnregisterSendSurface(&transfer_callback);

  // The initiator of the cancel should send a cancel frame to the other device,
  // then wait a few seconds before disconnecting to allow for processing on the
  // other device.
  EXPECT_TRUE(ExpectCancelFrame());
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  FastForward(kInitiatorCancelDelay);
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, CancelSenderNoninitiator) {
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  int64_t target_id =
      SetUpOutgoingShareTarget(transfer_callback, discovery_callback);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  SetUpOutgoingConnectionUntilAccept(transfer_callback, target_id);
  PayloadInfo info = AcceptAndSendPayload(transfer_callback, target_id);

  absl::Notification notification;
  EXPECT_CALL(transfer_callback,
              OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_EQ(share_target.id, target_id);
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kCancelled);
        notification.Notify();
      });
  EXPECT_FALSE(
      fake_nearby_connections_manager_->WasPayloadCanceled(info.payload->id));
  // The non-initiator of the cancellation processes a cancellation frame from
  // the initiator.
  SendCancel();
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_TRUE(
      fake_nearby_connections_manager_->WasPayloadCanceled(info.payload->id));

  // The non-initiator should close the connection immediately
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, CancelReceiverInitiator) {
  NiceMock<MockTransferUpdateCallback> transfer_callback;
  int64_t target_id = SetUpIncomingConnection(transfer_callback);
  ScopedReceiveSurface r(service_.get(), &transfer_callback);
  AcceptConnection(transfer_callback, target_id, kEndpointId);
  ASSERT_TRUE(ExpectPairedKeyEncryptionFrame());
  ASSERT_TRUE(ExpectPairedKeyResultFrame());

  absl::Notification notification;
  EXPECT_CALL(transfer_callback,
              OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_EQ(share_target.id, target_id);
        EXPECT_EQ(metadata.status(), TransferMetadata::Status::kCancelled);
      });
  EXPECT_FALSE(
      fake_nearby_connections_manager_->WasPayloadCanceled(kFilePayloadId));
  // The initiator of the cancellation explicitly calls Cancel().
  service_->Cancel(
      target_id, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(NearbySharingServiceImpl::StatusCodes::kOk, status_code);
        notification.Notify();
      });
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(
      fake_nearby_connections_manager_->WasPayloadCanceled(kFilePayloadId));

  // After the TransferMetadata::Status::kCancelled update, we expect other
  // classes to unregister the receive surface.
  UnregisterReceiveSurface(&transfer_callback);

  // This is a response frame generated by accept().
  GetWrittenFrame();
  // The initiator of the cancel should send a cancel frame to the other device,
  // then wait a few seconds before disconnecting to allow for processing on the
  // other device.
  ASSERT_TRUE(ExpectCancelFrame());
  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
  FastForward(kInitiatorCancelDelay);
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, CancelReceiverNoninitiator) {
  NiceMock<MockTransferUpdateCallback> transfer_callback;
  int64_t target_id = SetUpIncomingConnection(transfer_callback);
  ScopedReceiveSurface r(service_.get(), &transfer_callback);
  AcceptConnection(transfer_callback, target_id, kEndpointId);
  ExpectPairedKeyEncryptionFrame();
  ExpectPairedKeyResultFrame();

  absl::Notification notification;
  EXPECT_CALL(transfer_callback,
              OnTransferUpdate(testing::_, testing::_, testing::_))
      .WillOnce([&](const ShareTarget& share_target,
                    const AttachmentContainer& container,
                    TransferMetadata metadata) {
        EXPECT_EQ(target_id, share_target.id);
        EXPECT_EQ(TransferMetadata::Status::kCancelled, metadata.status());
        notification.Notify();
      });
  EXPECT_FALSE(
      fake_nearby_connections_manager_->WasPayloadCanceled(kFilePayloadId));
  // The non-initiator of the cancellation processes a cancellation frame from
  // the initiator.
  SendCancel();
  EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_TRUE(
      fake_nearby_connections_manager_->WasPayloadCanceled(kFilePayloadId));

  // The non-initiator should close the connection immediately
  EXPECT_FALSE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest,
       RegisterForegroundReceiveSurfaceEntersHighVisibility) {
  TestObserver observer(service_.get());
  NiceMock<MockTransferUpdateCallback> callback;

  SetLanIsConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_EVERYONE);
  local_device_data_manager()->SetDeviceName(kDeviceName);

  // To start, we should not be in high visibility state.
  EXPECT_FALSE(observer.in_high_visibility_);
  EXPECT_FALSE(observer.on_start_advertising_failure_called_);

  // If we register a foreground surface we should end up in high visibility
  // state.
  SetUpForegroundReceiveSurface(callback);
  ScopedReceiveSurface r(service_.get(), &callback);

  // At this point we should have a new high visibility state and the observer
  // should have been called as well.
  EXPECT_TRUE(observer.in_high_visibility_);
  EXPECT_FALSE(observer.on_start_advertising_failure_called_);

  // If we unregister the foreground receive surface we should no longer be in
  // high visibility and the observer should be notified.
  EXPECT_EQ(UnregisterReceiveSurface(&callback),
            NearbySharingService::StatusCodes::kOk);
  EXPECT_FALSE(observer.in_high_visibility_);

  // Remove the observer before it goes out of scope.
  service_->RemoveObserver(&observer);
  FlushTesting();
}

TEST_F(NearbySharingServiceImplTest, AddObserverSendsInitialAdapterState) {
  SetBluetoothIsPresent(true);
  SetBluetoothIsPowered(false);
  SetLanIsConnected(true);

  TestObserver observer(service_.get());
  FlushTesting();

  EXPECT_EQ(observer.bluetooth_state_,
            NearbySharingService::Observer::AdapterState::DISABLED);
  EXPECT_EQ(observer.lan_state_,
            NearbySharingService::Observer::AdapterState::ENABLED);

  // Remove the observer before it goes out of scope.
  service_->RemoveObserver(&observer);
}

TEST_F(NearbySharingServiceImplTest, AddObserverBluetoothAdapterUpdate) {
  SetBluetoothIsPresent(false);
  SetBluetoothIsPowered(false);
  SetLanIsConnected(false);

  TestObserver observer(service_.get());
  FlushTesting();
  EXPECT_EQ(observer.bluetooth_state_,
            NearbySharingService::Observer::AdapterState::NOT_PRESENT);

  SetBluetoothIsPresent(true);
  SetBluetoothIsPowered(false);
  EXPECT_EQ(observer.bluetooth_state_,
            NearbySharingService::Observer::AdapterState::DISABLED);

  SetBluetoothIsPresent(true);
  SetBluetoothIsPowered(true);
  EXPECT_EQ(observer.bluetooth_state_,
            NearbySharingService::Observer::AdapterState::ENABLED);

  SetBluetoothIsPresent(false);
  SetBluetoothIsPowered(true);
  EXPECT_EQ(observer.bluetooth_state_,
            NearbySharingService::Observer::AdapterState::NOT_PRESENT);

  // Remove the observer before it goes out of scope.
  service_->RemoveObserver(&observer);
}

TEST_F(NearbySharingServiceImplTest, AddObserverLanAdapterUpdate) {
  SetBluetoothIsPresent(false);
  SetBluetoothIsPowered(false);
  SetLanIsConnected(false);

  TestObserver observer(service_.get());
  FlushTesting();
  EXPECT_EQ(observer.lan_state_,
            NearbySharingService::Observer::AdapterState::DISABLED);

  SetLanIsConnected(true);
  EXPECT_EQ(observer.lan_state_,
            NearbySharingService::Observer::AdapterState::ENABLED);

  // Remove the observer before it goes out of scope.
  service_->RemoveObserver(&observer);
}

TEST_F(NearbySharingServiceImplTest, RotateBackgroundAdvertisementPeriodic) {
  certificate_manager()->set_next_salt({0x00, 0x01});
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  NiceMock<MockTransferUpdateCallback> callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  auto endpoint_info_initial =
      fake_nearby_connections_manager_->advertising_endpoint_info();

  certificate_manager()->set_next_salt({0x00, 0x02});
  FastForward(absl::Seconds(870));
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  auto endpoint_info_rotated =
      fake_nearby_connections_manager_->advertising_endpoint_info();
  EXPECT_NE(endpoint_info_initial, endpoint_info_rotated);
}

TEST_F(NearbySharingServiceImplTest,
       RotateBackgroundAdvertisementPrivateCertificatesChange) {
  certificate_manager()->set_next_salt({0x00, 0x01});
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  NiceMock<MockTransferUpdateCallback> callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  auto endpoint_info_initial =
      fake_nearby_connections_manager_->advertising_endpoint_info();

  certificate_manager()->set_next_salt({0x00, 0x02});
  certificate_manager()->NotifyPrivateCertificatesChanged();
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  auto endpoint_info_rotated =
      fake_nearby_connections_manager_->advertising_endpoint_info();
  EXPECT_NE(endpoint_info_initial, endpoint_info_rotated);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, OrderedEndpointDiscoveryEvents) {
  SetLanIsConnected(true);

  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;

  // Start discovering, to ensure a discovery listener is registered.
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  // Ensure that the endpoint discovered and lost event are process
  // sequentially. This is particularly important due to the asynchronous
  // operations needed to handle endpoint discovery.
  //
  // Order of events:
  //   - Nearby Connections discovers endpoint 1
  //   - Nearby Connections loses endpoint 1
  //   - Nearby Share processes discovered event.
  //   - endpoint 1 moved to discovery cache.
  //   - Nearby Connections discovers endpoint 2
  //   - Nearby Connections discovers endpoint 3
  //   - Nearby Connections loses endpoint 3
  //   - Nearby Connections loses endpoint 2
  //   - Nearby Share processes these 2 discovered events in order.
  //   - endpoints 2 and 3 moved to discovery cache.
  {
    absl::Notification notification;
    FindEndpoint(/*endpoint_id=*/"1");
    LoseEndpoint(/*endpoint_id=*/"1");
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
        .WillOnce([&](ShareTarget share_target) { notification.Notify(); });

    // Needed for discovery processing.
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true);
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
  {
    absl::Notification notification;
    FindEndpoint(/*endpoint_id=*/"2");
    FindEndpoint(/*endpoint_id=*/"3");
    LoseEndpoint(/*endpoint_id=*/"3");
    LoseEndpoint(/*endpoint_id=*/"2");
    InSequence s;
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
        .WillOnce([](ShareTarget share_target) {
          EXPECT_EQ(share_target.device_id, "2");
        });
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
        .WillOnce([&](ShareTarget share_target) {
          EXPECT_EQ(share_target.device_id, "3");
          notification.Notify();
        });

    // Needed for discovery processing. Fail, then the ShareTarget device ID is
    // set to the endpoint ID, which we use above to verify the correct endpoint
    // ID processing order.
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                             /*success=*/false);
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/3,
                                             /*success=*/false);

    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
}

TEST_F(NearbySharingServiceImplTest,
       RetryDiscoveredEndpointsNoDownloadIfDecryption) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  // Order of events:
  // - Discover endpoint 1 --> decrypts public certificate
  // - Fire certificate download timer --> no download because no cached
  //                                       advertisements
  {
    absl::Notification notification;
    FindEndpoint(/*endpoint_id=*/"1");
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered)
        .WillOnce([&](ShareTarget share_target) { notification.Notify(); });
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true);
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }

  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
}

TEST_F(NearbySharingServiceImplTest, DedupSameEndpointId) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  {
    absl::Notification notification;
    // vendor_id is default to 0.
    FindEndpoint(/*endpoint_id=*/"1");
    FindEndpointWithVendorId(
        /*endpoint_id=*/"1",
        static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));

    ::testing::InSequence s;
    ShareTarget share_target_1;
    ShareTarget share_target_2;
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(_))
        .WillOnce(SaveArg<0>(&share_target_1));

    EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_))
        .WillOnce([&](ShareTarget share_target) {
          share_target_2 = share_target;
          notification.Notify();
        });

    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/false);
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                             /*success=*/false);
    EXPECT_EQ(share_target_1.id, share_target_2.id);
    // Vendor_id updated.
    EXPECT_EQ(share_target_1.vendor_id, 0);
    EXPECT_EQ(share_target_2.vendor_id,
              static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
  Shutdown();
}

TEST_F(NearbySharingServiceImplTest,
       OnLostDedupSameEndpointIdBeforeExpiryNoOnShareTargetLost) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  {
    absl::Notification notification;
    ::testing::InSequence s;
    ShareTarget share_target_1;
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(_))
        .WillOnce(SaveArg<0>(&share_target_1));
    // vendor_id is default to 0.
    FindEndpoint(/*endpoint_id=*/"1");
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true);
    // Finish processing all the HandleEndpointDiscovered events.
    FlushTesting();

    // No call to OnShareTargetLost.
    LoseEndpoint(/*endpoint_id=*/"1");

    // Fastforward to just before the cache expiry time.
    FastForward(
        absl::Milliseconds(NearbyFlags::GetInstance().GetInt64Flag(
                               config_package_nearby::nearby_sharing_feature::
                                   kDiscoveryCacheLostExpiryMs) -
                           10));
    FindEndpointWithVendorId(
        /*endpoint_id=*/"1",
        static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    ShareTarget share_target_2;
    EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_))
        .WillOnce([&](ShareTarget share_target) {
          share_target_2 = share_target;
          notification.Notify();
        });

    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                             /*success=*/false);
    EXPECT_EQ(share_target_1.id, share_target_2.id);
    // Vendor_id updated.
    EXPECT_EQ(share_target_1.vendor_id, 0);
    EXPECT_EQ(share_target_2.vendor_id,
              static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
  Shutdown();
}

TEST_F(NearbySharingServiceImplTest, OnLostDedupSameEndpointIdAfterExpiry) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  {
    absl::Notification notification;
    ::testing::InSequence s;
    ShareTarget share_target_1;

    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(_))
        .WillOnce(SaveArg<0>(&share_target_1));
    // vendor_id is default to 0.
    FindEndpoint(/*endpoint_id=*/"1");
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/false);
    // Finish processing all the HandleEndpointDiscovered related events before
    // fast forwarding to avoid race condition.
    FlushTesting();

    ShareTarget share_target_1_lost;
    EXPECT_CALL(discovery_callback, OnShareTargetLost)
        .WillOnce(SaveArg<0>(&share_target_1_lost));
    LoseEndpoint(/*endpoint_id=*/"1");

    // Fast forward to after the cache expiry time.
    FastForward(
        absl::Milliseconds(NearbyFlags::GetInstance().GetInt64Flag(
                               config_package_nearby::nearby_sharing_feature::
                                   kDiscoveryCacheLostExpiryMs) +
                           10));
    FindEndpointWithVendorId(
        /*endpoint_id=*/"1",
        static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    ShareTarget share_target_2;
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(_))
        .WillOnce([&](ShareTarget share_target) {
          share_target_2 = share_target;
          notification.Notify();
        });

    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                             /*success=*/false);
    EXPECT_EQ(share_target_1_lost.id, share_target_1.id);
    // Cache entry expires and the share_target ID is not preserved.
    EXPECT_NE(share_target_1.id, share_target_2.id);

    EXPECT_EQ(share_target_1.vendor_id, 0);
    EXPECT_EQ(share_target_2.vendor_id,
              static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
}

// This test verifies the de-dup logic. Since certificates are the same, all the
// share targets are duplicates.
TEST_F(NearbySharingServiceImplTest, EndpointDedupBasedOnDeviceId) {
  // Make kDiscoveryCacheLostExpiryMs larger than
  // kCertificateDownloadDuringDiscoveryPeriod (10s).
  NearbyFlags::GetInstance().OverrideInt64FlagValue(
      config_package_nearby::nearby_sharing_feature::
          kDiscoveryCacheLostExpiryMs,
      20000);  // 20s
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  // Order of events:
  // - Discover endpoint 1 --> decrypts public certificate
  // - Discover endpoint 2 --> cannot decrypt public certificate
  // - Discover endpoint 3 --> decrypts public certificate
  //                       --> De-dup endpoint 1 with endpoint 3
  // - Discover endpoint 4 --> cannot decrypt public certificate
  // - Lose endpoint 3     --> endpoint 3 is added to discovery_cache
  // ----------------------------------------------------------------
  // - Fire certificate download timer --> certificates downloaded
  // - {x|y} can be 2 or 4, as the (Re)discover order is non-deterministic
  // - (Re)discover endpoints x before endpoint 3 discovery cache expiry
  //                            --> De-dup endpoint 3 with endpoint x
  // - (Re)discover endpoints y --> De-dup endpoint x with endpoint y
  {
    absl::Notification notification;
    ::testing::InSequence s;
    // vendor_id is default to 0.
    FindEndpoint(/*endpoint_id=*/"1");
    ShareTarget share_target_ep_1;
    EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(_))
        .WillOnce(SaveArg<0>(&share_target_ep_1));
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                             /*success=*/true);
    FlushTesting();

    FindInvalidEndpoint(/*endpoint_id=*/"2");
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                             /*success=*/false);
    FlushTesting();

    FindEndpointWithVendorId(
        /*endpoint_id=*/"3",
        static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    // Update endpoint 1 to endpoint 3
    ShareTarget share_target_ep_3;
    EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_))
        .WillOnce([&](ShareTarget share_target) {
          share_target_ep_3 = share_target;
        });
    // Update endpoint 3 to receive disabled after on lost.
    ShareTarget share_target_ep_3_disabled;
    EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_))
        .WillOnce([&](ShareTarget share_target) {
          share_target_ep_3_disabled = share_target;
          notification.Notify();
        });

    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/3,
                                             /*success=*/true,
                                             /*for_self_share=*/false,
                                             /*vendor_id*/ 1);
    FlushTesting();

    FindInvalidEndpoint(/*endpoint_id=*/"4");
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/4,
                                             /*success=*/false);
    FlushTesting();

    LoseEndpoint(/*endpoint_id=*/"3");
    FlushTesting();

    EXPECT_EQ(share_target_ep_1.id, share_target_ep_3.id);
    // Vendor_id updated.
    EXPECT_EQ(share_target_ep_3.vendor_id,
              static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
    EXPECT_FALSE(share_target_ep_3.receive_disabled);

    EXPECT_EQ(share_target_ep_1.id, share_target_ep_3_disabled.id);
    EXPECT_TRUE(share_target_ep_3_disabled.receive_disabled);
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }
  // kDiscoveryCacheLostExpiryMs is set to be larger than
  // kCertificateDownloadDuringDiscoveryPeriod so the cache_entry is unexpired.
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
  certificate_manager()->NotifyPublicCertificatesDownloaded();
  FlushTesting();
  ShareTarget share_target_updated;
  {
    absl::Notification notification;
    ::testing::InSequence s;
    // Update endpoint 3
    EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_)).Times(1);
    // One of the re-discovered endpoint updates the other one. The ordering
    // is non-deterministic.
    EXPECT_CALL(discovery_callback, OnShareTargetUpdated)
        .WillOnce([&](ShareTarget share_target) {
          share_target_updated = share_target;
          notification.Notify();
        });
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/5,
                                             /*success=*/true);
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/6,
                                             /*success=*/true);
    EXPECT_TRUE(notification.WaitForNotificationWithTimeout(kWaitTimeout));
  }

  FlushTesting();

  // Send Text to the updated endpoint.
  SetUpKeyVerification(
      /*is_incoming=*/false, PairedKeyResultFrame::SUCCESS);
  // Since we don't know exactly which endpoint is updated, we need to set the
  // token for both of them.
  fake_nearby_connections_manager_->SetRawAuthenticationToken(
      /*endpoint_id=*/"4", GetToken());
  fake_nearby_connections_manager_->SetRawAuthenticationToken(
      /*endpoint_id=*/"2", GetToken());
  fake_nearby_connections_manager_->set_nearby_connection(connection_.get());

  SetUpOutgoingConnectionUntilAccept(transfer_callback,
                                     share_target_updated.id);

  PayloadInfo info =
      AcceptAndSendPayload(transfer_callback, share_target_updated.id);
  FinishOutgoingTransfer(transfer_callback, share_target_updated.id,
                         /*complete=*/true, info);

  // Verify that the connection is established to one of the endpoints.
  std::string connected_endpoint_id;
  if (fake_nearby_connections_manager_
          ->connection_endpoint_info(/*endpoint_id=*/"4")
          .has_value()) {
    connected_endpoint_id = "4";
  }
  if (fake_nearby_connections_manager_
          ->connection_endpoint_info(/*endpoint_id=*/"2")
          .has_value()) {
    connected_endpoint_id = "2";
  }
  EXPECT_TRUE(connected_endpoint_id == "4" || connected_endpoint_id == "2");
  // Update endpoint 2 or 4 to receive disabled after disconnect.
  EXPECT_CALL(discovery_callback, OnShareTargetUpdated(_)).Times(1);
  // Call disconnect on the connection early before the timeout has passed.
  sharing_service_task_runner_->PostTask([this, connected_endpoint_id]() {
    fake_nearby_connections_manager_->Disconnect(connected_endpoint_id);
    // FakeNearbyConnectionsManager does not destroy the connection.
    connection_.reset();
  });
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  Shutdown();
}

TEST_F(NearbySharingServiceImplTest,
       RetryDiscoveredEndpointsDiscoveryRestartClearsCache) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  // Order of events:
  // - Discover endpoint 1 --> cannot decrypt public certificate
  // - Stop discovery
  // - Certificate download timer not running; not discovering
  // - Start discovery
  // - Fire certificate download timer --> certificates not downloaded; cached
  //                                       advertisement map has been cleared
  FindInvalidEndpoint(/*endpoint_id=*/"1");
  InSequence seq;
  EXPECT_CALL(discovery_callback, OnShareTargetDiscovered).Times(0);
  EXPECT_CALL(discovery_callback, OnShareTargetLost).Times(0);
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/false);
  UnregisterSendSurface(&transfer_callback);
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  // Note: Certificate downloads are also requested in RegisterSendSurface; this
  // is not related to the retry timer.
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
}

TEST_F(NearbySharingServiceImplTest,
       RetryDiscoveredEndpointsWhenCannotDecrypted) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  FindInvalidEndpoint(/*endpoint_id=*/"1");

  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/false);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  // Because there is one pending advertisement to resolve, it will cause public
  // certificates download.
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
  certificate_manager()->NotifyPublicCertificatesDownloaded();
  FlushTesting();
  // Don't download public certificates when it is tried.
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
  FlushTesting();
  // Don't download public certificates in case of the endpoint is discovered
  // again.
  FindInvalidEndpoint(/*endpoint_id=*/"1");
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/2,
                                           /*success=*/false);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u);
}

TEST_F(NearbySharingServiceImplTest, RetryDiscoveredEndpointsDownloadLimit) {
  // Start discovery.
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
  // Order of events:
  // - x3:
  //   - (Re)discover endpoint 1 --> cannot decrypt public certificate
  //   - Fire certificate download timer --> certificates downloaded
  // - Rediscover endpoint 1 --> cannot decrypt public certificate
  // - Fire certificate download timer --> no download; limit reached
  // - Restart discovery which resets limit counter
  for (size_t i = 1; i <= kMaxCertificateDownloadsDuringDiscovery; ++i) {
    FindInvalidEndpoint(/*endpoint_id=*/absl::StrCat(i));
  }

  for (size_t i = 1; i <= kMaxCertificateDownloadsDuringDiscovery; ++i) {
    SCOPED_TRACE(i);
    ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/i,
                                             /*success=*/false);
    FastForward(kCertificateDownloadDuringDiscoveryPeriod);
    EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
              1u + i);
    certificate_manager()->NotifyPublicCertificatesDownloaded();
    FlushTesting();
  }
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            1u + kMaxCertificateDownloadsDuringDiscovery);
  UnregisterSendSurface(&transfer_callback);
  RegisterSendSurface(&transfer_callback, &discovery_callback,
                      SendSurfaceState::kForeground);
  // Note: Certificate downloads are also requested in RegisterSendSurface; this
  // is not related to the retry timer.
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            2u + kMaxCertificateDownloadsDuringDiscovery);
  FindInvalidEndpoint(/*endpoint_id=*/"1");
  ProcessLatestPublicCertificateDecryption(
      /*expected_num_calls=*/1u + kMaxCertificateDownloadsDuringDiscovery,
      /*success=*/false);
  FastForward(kCertificateDownloadDuringDiscoveryPeriod);
  EXPECT_EQ(certificate_manager()->num_download_public_certificates_calls(),
            3u + kMaxCertificateDownloadsDuringDiscovery);
}

TEST_F(NearbySharingServiceImplTest,
       ScreenLockedRegisterReceiveSurfaceNotAdvertising) {
  SetScreenLocked(true);
  SetLanConnected(true);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest, BlockTargetWithSameVendorId) {
  InSequence seq;
  // Register send surface with vendor ID 1 that requests blocking.
  MockTransferUpdateCallback callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  ASSERT_EQ(RegisterSendSurface(&callback, &discovery_callback,
                                SendSurfaceState::kForeground,
                                Advertisement::BlockedVendorId::kSamsung),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &callback);
  // Verify service will not report discovered.
  EXPECT_CALL(discovery_callback, OnShareTargetDiscovered(testing::_)).Times(0);
  // Find endpoint with vendor ID 1.
  FindEndpointWithVendorId(
      /*endpoint_id=*/"1",
      static_cast<uint8_t>(Advertisement::BlockedVendorId::kSamsung));
  ProcessLatestPublicCertificateDecryption(/*expected_num_calls=*/1,
                                           /*success=*/false);
}

TEST_F(NearbySharingServiceImplTest,
       RegisterSendSurfaceWithDifferentVendorIdIsBlocked) {
  SetLanConnected(true);
  preference_manager().SetInteger(
      prefs::kNearbySharingBackgroundVisibilityName,
      static_cast<int>(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS));
  FlushTesting();

  // Register background send surface with vendor ID 1.
  MockShareTargetDiscoveredCallback background_discovered_callback;
  MockTransferUpdateCallback background_transfer_callback;
  NearbySharingService::StatusCodes result = RegisterSendSurface(
      &background_transfer_callback, &background_discovered_callback,
      NearbySharingService::SendSurfaceState::kBackground,
      Advertisement::BlockedVendorId::kSamsung);
  ASSERT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &background_transfer_callback);
  // Register foreground send surface with different vendor ID.
  MockShareTargetDiscoveredCallback foreground_discovered_callback;
  MockTransferUpdateCallback foreground_transfer_callback;
  result = RegisterSendSurface(
      &foreground_transfer_callback, &foreground_discovered_callback,
      NearbySharingService::SendSurfaceState::kForeground,
      static_cast<Advertisement::BlockedVendorId>(2));
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kInvalidArgument);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest, ScreenLocksDuringAdvertising) {
  SetLanConnected(true);
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());

  SetScreenLocked(true);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());

  SetScreenLocked(false);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
  EXPECT_FALSE(fake_nearby_connections_manager_->is_shutdown());
}

TEST_F(NearbySharingServiceImplTest, ScreenLocksDuringDiscovery) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;
  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  SetScreenLocked(true);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsDiscovering());
  SetScreenLocked(false);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());
}

TEST_F(NearbySharingServiceImplTest, CreateShareTarget) {
  std::unique_ptr<Advertisement> advertisement = Advertisement::NewInstance(
      GetNearbyShareTestEncryptedMetadataKey().salt(),
      GetNearbyShareTestEncryptedMetadataKey().encrypted_key(), kDeviceType,
      kDeviceName, kVendorId);

  // Flip |for_self_share| to true to ensure the resulting ShareTarget picks
  // this up.
  nearby::sharing::proto::PublicCertificate certificate_proto =
      GetNearbyShareTestPublicCertificate(
          DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  certificate_proto.set_for_self_share(true);

  std::optional<NearbyShareDecryptedPublicCertificate> certificate =
      NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
          certificate_proto, GetNearbyShareTestEncryptedMetadataKey());
  ASSERT_TRUE(certificate.has_value());
  ASSERT_EQ(certificate_proto.for_self_share(), certificate->for_self_share());

  std::optional<ShareTarget> share_target = service_->CreateShareTarget(
      kEndpointId, *advertisement, certificate, /*is_incoming=*/true);

  ASSERT_TRUE(share_target.has_value());
  EXPECT_EQ(kDeviceName, share_target->device_name);
  EXPECT_EQ(kDeviceType, share_target->type);
  EXPECT_EQ(certificate_proto.for_self_share(), share_target->for_self_share);

  // Test when |certificate| is null.
  share_target = service_->CreateShareTarget(kEndpointId, *advertisement,
                                             /*certificate=*/std::nullopt,
                                             /*is_incoming=*/true);
  ASSERT_TRUE(share_target.has_value());
  EXPECT_EQ(kDeviceName, share_target->device_name);
  EXPECT_EQ(kDeviceType, share_target->type);
  EXPECT_EQ(kVendorId, share_target->vendor_id);
  EXPECT_FALSE(share_target->for_self_share);
}

TEST_F(NearbySharingServiceImplTest, SelfShareAutoAccept) {
  // We create an incoming connection corresponding to a certificate where the
  // |for_self_share| field is set to 'true'. This value will be propagated to
  // the ShareTarget, which will be used as a signal for the service to
  // automatically accept the transfer when Self Share is enabled. This is
  // similar to other tests (see "AcceptValidShareTarget") but without the
  // explicit call to service_->Accept().
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id =
      SetUpIncomingConnection(callback, /*is_foreground=*/false,
                              /*for_self_share=*/true);
  ScopedReceiveSurface r(service_.get(), &callback);

  // Should fail to call accept.
  service_->Accept(
      share_target_id, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code,
                  NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall);
      });

  // Check data written to connection_.
  ExpectPairedKeyEncryptionFrame();
  ExpectPairedKeyResultFrame();
  ExpectConnectionResponseFrame(ConnectionResponseFrame::ACCEPT);

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());

  FlushTesting();
}

TEST_F(NearbySharingServiceImplTest, SelfShareNoAutoAcceptInForeground) {
  NiceMock<MockTransferUpdateCallback> callback;
  int64_t share_target_id =
      SetUpIncomingConnection(callback, /*is_foreground=*/true,
                              /*for_self_share=*/true);
  ScopedReceiveSurface r(service_.get(), &callback);

  EXPECT_CALL(callback, OnTransferUpdate(testing::_, testing::_, testing::_))
      .Times(0);

  service_->Accept(
      share_target_id, [&](NearbySharingServiceImpl::StatusCodes status_code) {
        EXPECT_EQ(status_code,
                  NearbySharingServiceImpl::StatusCodes::kOutOfOrderApiCall);
      });

  // Check data written to connection_.
  ExpectPairedKeyEncryptionFrame();
  ExpectPairedKeyResultFrame();
  ExpectConnectionResponseFrame(ConnectionResponseFrame::ACCEPT);

  EXPECT_TRUE(
      fake_nearby_connections_manager_->connection_endpoint_info(kEndpointId)
          .has_value());
}

TEST_F(NearbySharingServiceImplTest, ObserveAccountLoginAndLogout) {
  MockAccountObserver account_observer;
  absl::Notification notification;
  service_->GetAccountManager()->AddObserver(&account_observer);

  EXPECT_CALL(account_observer, OnLoginSucceeded(kTestAccountId)).Times(1);
  AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  account_manager().NotifyLogin(kTestAccountId);
  EXPECT_CALL(account_observer, OnLogoutSucceeded(kTestAccountId, false))
      .Times(1);
  absl::Notification logout_notification;
  service_->GetAccountManager()->Logout([&](absl::Status status) {
    EXPECT_TRUE(status.ok());
    logout_notification.Notify();
  });
  EXPECT_TRUE(logout_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  service_->GetAccountManager()->RemoveObserver(&account_observer);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, LoginAndLogoutShouldResetSettings) {
  SetLanConnected(true);

  // Used to check whether the setting is cleared after login.
  service_->GetSettings()->SetIsAnalyticsEnabled(true);

  std::string device_id =
      preference_manager_.GetString(prefs::kNearbySharingDeviceIdName, "");
  EXPECT_TRUE(device_id.empty());

  // Create account.
  AccountManager::Account account;
  account.id = kTestAccountId;

  // Login user.
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  account_manager().NotifyLogin(kTestAccountId);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_TRUE(service_->GetSettings()->GetIsAnalyticsEnabled());
  ASSERT_TRUE(service_->GetAccountManager()->GetCurrentAccount().has_value());
  EXPECT_EQ(service_->GetAccountManager()->GetCurrentAccount()->id,
            kTestAccountId);
  device_id =
      preference_manager_.GetString(prefs::kNearbySharingDeviceIdName, "");
  EXPECT_FALSE(device_id.empty());
  EXPECT_EQ(device_id.size(), 10u);
  for (const char c : device_id) EXPECT_TRUE(std::isalnum(c));

  // Logout user.
  absl::Notification logout_notification;
  service_->GetAccountManager()->Logout([&](absl::Status status) {
    EXPECT_TRUE(status.ok());
    logout_notification.Notify();
  });
  EXPECT_TRUE(logout_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  absl::SleepFor(absl::Milliseconds(100));
  // data collection flag is not reset on logout.
  EXPECT_TRUE(service_->GetSettings()->GetIsAnalyticsEnabled());
  EXPECT_FALSE(service_->GetAccountManager()->GetCurrentAccount().has_value());
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  device_id =
      preference_manager_.GetString(prefs::kNearbySharingDeviceIdName, "");
  EXPECT_TRUE(device_id.empty());
}

TEST_F(NearbySharingServiceImplTest, LoginShouldSetContactsVisibility) {
  SetLanConnected(true);

  // Create account.
  AccountManager::Account account;
  account.id = kTestAccountId;

  // Login user.
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  account_manager().NotifyLogin(kTestAccountId);
  ASSERT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  EXPECT_EQ(service_->GetSettings()->GetVisibility(),
            DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
}

TEST_F(NearbySharingServiceImplTest, LogoutShouldSetValidVisibility) {
  SetLanConnected(true);

  // Create account.
  AccountManager::Account account;
  account.id = kTestAccountId;

  // Login user.
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  // Set visibility.
  service_->GetSettings()->SetVisibility(
      DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE);

  // Logout user.
  absl::Notification logout_notification;
  service_->GetAccountManager()->Logout([&](absl::Status status) {
    EXPECT_TRUE(status.ok());
    logout_notification.Notify();
  });
  EXPECT_TRUE(logout_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_EQ(service_->GetSettings()->GetVisibility(),
            DeviceVisibility::DEVICE_VISIBILITY_HIDDEN);

  // Login user.
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt2 =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));

  // Set visibility.
  service_->GetSettings()->SetVisibility(
      DeviceVisibility::DEVICE_VISIBILITY_EVERYONE);

  // Logout user.
  absl::Notification logout2_notification;
  service_->GetAccountManager()->Logout([&](absl::Status status) {
    EXPECT_TRUE(status.ok());
    logout2_notification.Notify();
  });
  EXPECT_TRUE(
      logout2_notification.WaitForNotificationWithTimeout(kWaitTimeout));
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_EQ(service_->GetSettings()->GetVisibility(),
            DeviceVisibility::DEVICE_VISIBILITY_EVERYONE);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest, LoginAndLogoutNoStopRunningSurfaces) {
  SetLanConnected(true);
  MockTransferUpdateCallback transfer_callback;
  MockShareTargetDiscoveredCallback discovery_callback;

  EXPECT_EQ(RegisterSendSurface(&transfer_callback, &discovery_callback,
                                SendSurfaceState::kForeground),
            NearbySharingService::StatusCodes::kOk);
  ScopedSendSurface s(service_.get(), &transfer_callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  // Set an account and use it to login.
  AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);
  std::unique_ptr<SigninAttempt> signin_attempt =
      service_->GetAccountManager()->Login("test_client_id",
                                           "test_client_secret");
  EXPECT_TRUE(fake_nearby_connections_manager_->IsDiscovering());

  // Logout user.
  absl::Notification logout_notification;
  service_->GetAccountManager()->Logout([&](absl::Status status) {
    EXPECT_TRUE(status.ok());
    logout_notification.Notify();
  });
  EXPECT_TRUE(logout_notification.WaitForNotificationWithTimeout(kWaitTimeout));
}

TEST_F(NearbySharingServiceImplTest,
       IsReceivingEnabledWithRegisterReceiveSurfaceForeground) {
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_ALL_CONTACTS);
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       IsReceivingDisabledWithRegisterReceiveSurfaceForeground) {
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       IsReceivingEnabledWithRegisterReceiveSurfaceBackground) {
  MockTransferUpdateCallback callback;
  service_->GetSettings()->SetVisibility(
      DeviceVisibility::DEVICE_VISIBILITY_SELF_SHARE);
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_TRUE(sharing_service_task_runner_->SyncWithTimeout(kTaskWaitTimeout));
  EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest,
       IsReceivingDisabledWithRegisterReceiveSurfaceBackground) {
  MockTransferUpdateCallback callback;
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kBackground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, NoAdvertisingWhenHidden) {
  MockTransferUpdateCallback callback;
  SetVisibility(DeviceVisibility::DEVICE_VISIBILITY_HIDDEN);
  NearbySharingService::StatusCodes result = RegisterReceiveSurface(
      &callback, NearbySharingService::ReceiveSurfaceState::kForeground);
  EXPECT_EQ(result, NearbySharingService::StatusCodes::kOk);
  ScopedReceiveSurface r(service_.get(), &callback);
  EXPECT_FALSE(fake_nearby_connections_manager_->IsAdvertising());
}

TEST_F(NearbySharingServiceImplTest, RemoveIncomingPayloads) {
  fake_nearby_connections_manager_->AddUnknownFilePathsToDeleteForTesting(
      FilePath{"test1.txt"});
  fake_nearby_connections_manager_->AddUnknownFilePathsToDeleteForTesting(
      FilePath{"test2.txt"});
  auto unknown_file_paths_to_delete =
      fake_nearby_connections_manager_->GetUnknownFilePathsToDeleteForTesting();
  EXPECT_EQ(unknown_file_paths_to_delete.size(), 2);
  EXPECT_THAT(
      unknown_file_paths_to_delete,
      UnorderedElementsAre(FilePath("test1.txt"), FilePath("test2.txt")));
  nearby::analytics::MockEventLogger mock_event_logger;
  analytics::AnalyticsRecorder analytics_recorder{/*vendor_id=*/0,
                                                  &mock_event_logger};
  ShareTarget share_target;
  share_target.is_incoming = true;
  IncomingShareSession session(
      fake_context_.fake_clock(), *sharing_service_task_runner_,
      fake_nearby_connections_manager_, analytics_recorder, "endpoint_id",
      share_target,
      [](const IncomingShareSession&, const TransferMetadata&) {});
  service_->RemoveIncomingPayloads(session);
  EXPECT_EQ(
      fake_nearby_connections_manager_->GetUnknownFilePathsToDeleteForTesting()
          .size(),
      0);

  // Test GetAndClearUnknownFilePathsToDelete
  fake_nearby_connections_manager_->AddUnknownFilePathsToDeleteForTesting(
      FilePath{"test1.txt"});
  fake_nearby_connections_manager_->AddUnknownFilePathsToDeleteForTesting(
      FilePath{"test2.txt"});
  unknown_file_paths_to_delete =
      fake_nearby_connections_manager_->GetAndClearUnknownFilePathsToDelete();
  EXPECT_EQ(unknown_file_paths_to_delete.size(), 2);
  EXPECT_EQ(
      fake_nearby_connections_manager_->GetUnknownFilePathsToDeleteForTesting()
          .size(),
      0);
}

TEST_F(NearbySharingServiceImplTest, NotifyLogoutSucceededWithCredentialError) {
  TestObserver observer(service_.get());
  ::nearby::AccountManager::Account account;
  account.id = kTestAccountId;
  account_manager().SetAccount(account);

  account_manager().NotifyCredentialError();
  FlushTesting();

  EXPECT_TRUE(observer.credential_error_called_);

  // Remove the observer before it goes out of scope.
  service_->RemoveObserver(&observer);
  FlushTesting();
}

}  // namespace NearbySharingServiceUnitTests
}  // namespace nearby::sharing
